Ticket #1252: ssl-v4.patch
File ssl-v4.patch, 20.2 KB (added by , 6 years ago) |
---|
-
xpra/net/bytestreams.py
9 9 import os 10 10 import errno 11 11 import socket 12 import ssl 12 13 13 14 from xpra.log import Logger 14 15 log = Logger("network", "protocol") … … 104 105 except TypeError: 105 106 log.warn("untilConcludes error calling %s with %s", f, a) 106 107 raise 108 except (ssl.SSLError, ssl.SSLWantReadError, ssl.SSLWantWriteError) as e: 109 log("untilConcludes(%s, %s, %s, %s) %s - waiting for more data", is_active_cb, f, a, kw, type(e)) 110 continue 107 111 except (IOError, OSError) as e: 108 112 code = e.args[0] 109 113 can_continue = CONTINUE.get(code) … … 115 119 continue 116 120 abort = ABORT.get(code, code) 117 121 if abort is not None: 122 log("untilConcludes: %s, args=%s, code=%s, abort=%s", type(e), e.args, code, abort) 118 123 raise ConnectionClosedException(e) 119 124 log("untilConcludes(%s, %s, %s, %s) %s / %s (raised)", is_active_cb, f, a, kw, abort, e) 120 125 raise -
xpra/net/net_util.py
253 253 except: 254 254 return {} 255 255 256 def get_ssl_caps(): 257 try: 258 import ssl 259 except ImportError as e: 260 log("no ssl: %s", e) 261 return {} 262 protocols = [k[len("PROTOCOLS_"):] for k in dir(ssl) if k.startswith("PROTOCOL_")] 263 return { 264 "ssl" : True, 265 "protocols" : protocols, 266 } 267 268 def get_ssl_info(): 269 try: 270 import ssl 271 except ImportError as e: 272 log("no ssl: %s", e) 273 return {} 274 protocols = dict((k,getattr(ssl, k)) for k in dir(ssl) if k.startswith("PROTOCOL_")) 275 ops = dict((k,getattr(ssl, k)) for k in dir(ssl) if k.startswith("OP_")) 276 vers = dict((k,getattr(ssl, k)) for k in dir(ssl) if k.startswith("VERIFY_")) 277 info = { 278 "protocols" : protocols, 279 "options" : ops, 280 "verify" : vers, 281 } 282 for k,name in { 283 "HAS_ALPN" : "alpn", 284 "HAS_ECDH" : "ecdh", 285 "HAS_SNI" : "sni", 286 "HAS_NPN" : "npn", 287 "CHANNEL_BINDING_TYPES" : "channel-binding-types", 288 }.items(): 289 v = getattr(ssl, k, None) 290 if v is not None: 291 info[name] = v 292 for k,name in { 293 "OPENSSL_VERSION" : "version", 294 "OPENSSL_VERSION_INFO" : "version-info", 295 "OPENSSL_VERSION_NUMBER": "version-number", 296 }.items(): 297 v = getattr(ssl, k, None) 298 if v is not None: 299 info.setdefault("openssl", {})[name] = v 300 return info 301 256 302 def get_info(): 257 303 from xpra.net.protocol import get_network_caps 258 304 i = get_network_caps() -
xpra/net/protocol.py
66 66 67 67 68 68 def get_network_caps(): 69 from xpra.net.net_util import get_ssl_caps 69 70 try: 70 71 from xpra.net.mmap_pipe import can_use_mmap 71 72 mmap = can_use_mmap() … … 76 77 "compressors" : compression.get_enabled_compressors(), 77 78 "encoders" : packet_encoding.get_enabled_encoders(), 78 79 "mmap" : mmap, 80 "ssl" : get_ssl_caps(), 79 81 } 80 82 caps.update(get_crypto_caps()) 81 83 caps.update(get_compression_caps()) … … 560 562 callback() 561 563 log("io_thread_loop(%s, %s) loop ended, closed=%s", name, callback, self._closed) 562 564 except ConnectionClosedException as e: 565 log("%s closed", self._conn, exc_info=True) 563 566 if not self._closed: 564 567 #ConnectionClosedException means the warning has been logged already 565 568 self._connection_lost("%s connection %s closed" % (name, self._conn)) -
xpra/scripts/config.py
340 340 "exec-wrapper" : str, 341 341 "dbus-launch" : str, 342 342 "webcam" : str, 343 #ssl options: 344 "ssl-key" : str, 345 "ssl-cert" : str, 346 "ssl-version" : str, 347 "ssl-ca-certs" : str, 348 "ssl-ciphers" : str, 349 "ssl-client-verify-mode" : str, 350 "ssl-server-verify-mode" : str, 351 "ssl-verify-flags" : str, 352 "ssl-check-hostname": bool, 343 353 #int options: 344 354 "quality" : int, 345 355 "min-quality" : int, … … 411 421 "bind" : list, 412 422 "bind-vsock" : list, 413 423 "bind-tcp" : list, 424 "bind-ssl" : list, 414 425 "start-env" : list, 415 426 "env" : list, 416 427 } … … 523 534 "exec-wrapper" : "", 524 535 "dbus-launch" : "dbus-launch --close-stderr", 525 536 "webcam" : ["auto", "no"][OSX], 537 #ssl options: 538 "ssl-key" : "", 539 "ssl-cert" : "", 540 "ssl-version" : "TLSv1_2", 541 "ssl-ca-certs" : "default", 542 "ssl-ciphers" : "DEFAULT", 543 "ssl-client-verify-mode" : "optional", 544 "ssl-server-verify-mode" : "required", 545 "ssl-verify-flags" : "CHECK_CHAIN,X509_STRICT", 546 "ssl-check-hostname": True, 526 547 "quality" : 0, 527 548 "min-quality" : 30, 528 549 "speed" : 0, … … 588 609 "bind" : bind_dirs, 589 610 "bind-vsock" : [], 590 611 "bind-tcp" : [], 612 "bind-ssl" : [], 591 613 "start" : [], 592 614 "start-child" : [], 593 615 "start-after-connect" : [], -
xpra/scripts/main.py
147 147 platform_clean() 148 148 149 149 150 151 150 def do_replace_option(cmdline, oldoption, newoption): 152 151 if oldoption in cmdline: 153 152 cmdline.remove(oldoption) … … 405 404 metavar="[HOST]:PORT", 406 405 help="Listen for connections over TCP (use --tcp-auth to secure it)." 407 406 + " You may specify this option multiple times with different host and port combinations") 407 group.add_option("--bind-ssl", action="append", 408 dest="bind_ssl", default=list(defaults.bind_ssl or []), 409 metavar="[HOST]:PORT", 410 help="Listen for connections over SSL (use --ssl-auth to secure it)." 411 + " You may specify this option multiple times with different host and port combinations") 408 412 else: 413 ignore({"bind" : []}) 409 414 ignore({"bind-tcp" : []}) 415 ignore({"bind-ssl" : []}) 410 416 try: 411 417 from xpra.net import vsock 412 418 except: … … 675 681 dest="keyboard_sync", default=defaults.keyboard_sync, 676 682 help="Synchronize keyboard state. Default: %s." % enabled_str(defaults.keyboard_sync)) 677 683 684 group = optparse.OptionGroup(parser, "SSL Options", 685 "These options apply to both client and server. Please refer to the man page for details.") 686 parser.add_option_group(group) 687 group.add_option("--ssl-key", action="store", 688 dest="ssl_key", default=defaults.ssl_key, 689 help="Key file to use. Default: '%default'.") 690 group.add_option("--ssl-cert", action="store", 691 dest="ssl_cert", default=defaults.ssl_cert, 692 help="Certifcate file to use. Default: '%default'.") 693 group.add_option("--ssl-version", action="store", 694 dest="ssl_version", default=defaults.ssl_version, 695 help="Specifies which version of the SSL protocol to use. Default: '%default'.") 696 group.add_option("--ssl-ca-certs", action="store", 697 dest="ssl_ca_certs", default=defaults.ssl_ca_certs, 698 help="The ca_certs file contains a set of concatenated 'certification authority' certificates. Default: '%default'.") 699 group.add_option("--ssl-ciphers", action="store", 700 dest="ssl_ciphers", default=defaults.ssl_ciphers, 701 help="Sets the available ciphers for this SSL object. It should be a string in the OpenSSL cipher list format. Default: '%default'.") 702 group.add_option("--ssl-client-verify-mode", action="store", 703 dest="ssl_client_verify_mode", default=defaults.ssl_client_verify_mode, 704 help="Whether to try to verify the client's certificates and how to behave if verification fails. Default: '%default'.") 705 group.add_option("--ssl-server-verify-mode", action="store", 706 dest="ssl_server_verify_mode", default=defaults.ssl_server_verify_mode, 707 help="Whether to try to verify the server's certificates and how to behave if verification fails. Default: '%default'.") 708 group.add_option("--ssl-verify-flags", action="store", 709 dest="ssl_verify_flags", default=defaults.ssl_verify_flags, 710 help="The flags for certificate verification operations. Default: '%default'.") 711 group.add_option("--ssl-check-hostname", action="store", metavar="yes|no", 712 dest="ssl_check_hostname", default=defaults.ssl_check_hostname, 713 help="Wether to match the peer cert's hostname. Default: '%s'." % enabled_str(defaults.windows)) 714 678 715 group = optparse.OptionGroup(parser, "Advanced Options", 679 716 "These options apply to both client and server. Please refer to the man page for details.") 680 717 parser.add_option_group(group) … … 1142 1179 host = "127.0.0.1" 1143 1180 desc["host"] = host 1144 1181 return username, password, host, port 1145 1182 1146 1183 if display_name.lower().startswith("ssh:") or display_name.lower().startswith("ssh/"): 1147 1184 separator = display_name[3] # ":" or "/" 1148 1185 desc.update({ … … 1230 1267 if opts.socket_dir: 1231 1268 desc["socket_dir"] = opts.socket_dir 1232 1269 return desc 1233 elif display_name.startswith("tcp:") or display_name.startswith("tcp/"): 1270 elif display_name.startswith("tcp:") or display_name.startswith("tcp/") or \ 1271 display_name.startswith("ssl:") or display_name.startswith("ssl/"): 1272 ctype = display_name[:3] #ie: "ssl" or "tcp" 1234 1273 separator = display_name[3] # ":" or "/" 1235 1274 desc.update({ 1236 "type" : "tcp",1275 "type" : ctype, 1237 1276 "local" : False, 1238 1277 }) 1239 1278 parts = display_name.split(separator) 1240 1279 if len(parts) not in (2, 3, 4): 1241 error_cb("invalid tcp connection string, use tcp/[username[:password]@]host:port[/display] or tcp:[username[:password]@]host:port")1280 error_cb("invalid %s connection string, use %s/[username[:password]@]host:port[/display] or %s:[username[:password]@]host:port" % (ctype * 3)) 1242 1281 #display (optional): 1243 1282 if separator=="/" and len(parts)==3: 1244 1283 display = parts[2] … … 1336 1375 sock.settimeout(None) 1337 1376 return SocketConnection(sock, sock.getsockname(), sock.getpeername(), description, dtype) 1338 1377 1339 def connect_or_fail(display_desc ):1378 def connect_or_fail(display_desc, opts): 1340 1379 try: 1341 return connect_to(display_desc )1380 return connect_to(display_desc, opts) 1342 1381 except InitException: 1343 1382 raise 1344 1383 except Exception as e: … … 1354 1393 #run in a new session 1355 1394 os.setsid() 1356 1395 1357 def connect_to(display_desc, debug_cb=None, ssh_fail_cb=ssh_connect_failed):1396 def connect_to(display_desc, opts=None, debug_cb=None, ssh_fail_cb=ssh_connect_failed): 1358 1397 display_name = display_desc["display_name"] 1359 1398 dtype = display_desc["type"] 1360 1399 conn = None … … 1494 1533 from xpra.net.bytestreams import SocketConnection 1495 1534 return SocketConnection(sock, "local", "host", (CID_TYPES.get(cid, cid), iport), dtype) 1496 1535 1497 elif dtype == "tcp":1536 elif dtype in ("tcp", "ssl"): 1498 1537 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1499 1538 sock.settimeout(SOCKET_TIMEOUT) 1500 1539 sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, TCP_NODELAY) 1540 if dtype == "ssl": 1541 import ssl 1542 cert_reqs, ssl_version, ssl_ca_certs = parse_ssl_attributes(opts.ssl_server_verify_mode, opts.ssl_version, opts.ssl_cert) 1543 sock = ssl.wrap_socket(sock, keyfile=opts.ssl_key, certfile=opts.ssl_cert, 1544 server_side=False, cert_reqs=cert_reqs, 1545 ssl_version=ssl_version, ca_certs=ssl_ca_certs, 1546 do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=opts.ssl_ciphers) 1547 1501 1548 tcp_endpoint = (display_desc["host"], display_desc["port"]) 1502 1549 conn = _socket_connect(sock, tcp_endpoint, display_name, dtype) 1503 1550 conn.timeout = SOCKET_TIMEOUT 1504 1505 1551 else: 1506 1552 assert False, "unsupported display type in connect: %s" % dtype 1507 1553 return conn 1508 1554 1555 def parse_ssl_attributes(verify_mode, ssl_version_str, ca_certs): 1556 import ssl 1557 cert_reqs = getattr(ssl, "CERT_%s" % verify_mode.upper(), None) 1558 if cert_reqs is None: 1559 values = [k[len("CERT_"):].lower() for k in dir(ssl) if k.startswith("CERT_")] 1560 raise InitException("invalid ssl-server-verify-mode '%s', must be one of: %s" % (verify_mode, csv(values))) 1561 ssl_version = getattr(ssl, "PROTOCOL_%s" % ssl_version_str, None) 1562 if ssl_version is None: 1563 values = [k[len("PROTOCOL_"):] for k in dir(ssl) if k.startswith("PROTOCOL_")] 1564 raise InitException("invalid ssl-version '%s', must be one of: %s" % (ssl_version_str, csv(values))) 1565 ssl_ca_certs = ca_certs 1566 if ssl_ca_certs=="default": 1567 ssl_ca_certs = None 1568 return cert_reqs, ssl_version, ssl_ca_certs 1569 1570 1509 1571 def get_sockpath(display_desc, error_cb): 1510 1572 #if the path was specified, use that: 1511 1573 sockpath = display_desc.get("socket_path") … … 1531 1593 error_cb("Quality must be between 0 and 100 inclusive. (or -1 to disable)") 1532 1594 1533 1595 def connect(): 1534 return connect_or_fail(pick_display(error_cb, opts, extra_args) )1596 return connect_or_fail(pick_display(error_cb, opts, extra_args), opts) 1535 1597 1536 1598 if mode=="screenshot": 1537 1599 from xpra.client.gobject_client_base import ScreenshotXpraClient … … 1675 1737 app = make_client(error_cb, opts) 1676 1738 app.init(opts) 1677 1739 app.init_ui(opts) 1678 conn = connect_or_fail(params )1740 conn = connect_or_fail(params, opts) 1679 1741 app.setup_connection(conn) 1680 1742 do_run_client(app) 1681 1743 … … 1877 1939 else: 1878 1940 #use display specified on command line: 1879 1941 display = pick_display(error_cb, opts, args) 1880 server_conn = connect_or_fail(display )1942 server_conn = connect_or_fail(display, opts) 1881 1943 from xpra.net.bytestreams import TwoFileConnection 1882 1944 app = XpraProxy("xpra-pipe-proxy", TwoFileConnection(sys.stdout, sys.stdin, info="stdin/stdout"), server_conn) 1883 1945 signal.signal(signal.SIGINT, app.quit) … … 1922 1984 return 1 1923 1985 1924 1986 display_desc = pick_display(error_cb, opts, extra_args) 1925 conn = connect_or_fail(display_desc )1987 conn = connect_or_fail(display_desc, opts) 1926 1988 app = None 1927 1989 e = 1 1928 1990 try: -
xpra/scripts/server.py
346 346 listener.bind(sockaddr) 347 347 return listener 348 348 349 def setup_tcp_socket(host, iport ):349 def setup_tcp_socket(host, iport, socktype="TCP"): 350 350 from xpra.log import Logger 351 351 log = Logger("network") 352 352 try: 353 353 tcp_socket = create_tcp_socket(host, iport) 354 354 except Exception as e: 355 raise InitException("failed to setup TCP socket on %s:%s %s" % (host, iport, e))355 raise InitException("failed to setup %s socket on %s:%s %s" % (socktype, host, iport, e)) 356 356 def cleanup_tcp_socket(): 357 log.info("closing tcp socket %s:%s", host, iport)357 log.info("closing %s socket %s:%s", socktype, host, iport) 358 358 try: 359 359 tcp_socket.close() 360 360 except: … … 362 362 _cleanups.append(cleanup_tcp_socket) 363 363 return "tcp", tcp_socket, (host, iport) 364 364 365 def setup_ssl_socket(opts, host, iport): 366 _, tcp_socket, host_port = setup_tcp_socket(host, iport, "SSL") 367 if not opts.ssl_cert: 368 raise InitException("you must specify an 'ssl-cert' file to use 'bind-ssl' sockets") 369 import ssl 370 from xpra.scripts.main import parse_ssl_attributes 371 cert_reqs, ssl_version, ssl_ca_certs = parse_ssl_attributes(opts.ssl_client_verify_mode, opts.ssl_version, opts.ssl_cert) 372 ssl_sock = ssl.wrap_socket(tcp_socket, keyfile=opts.ssl_key, certfile=opts.ssl_cert, 373 server_side=True, cert_reqs=cert_reqs, 374 ssl_version=ssl_version, ca_certs=ssl_ca_certs, 375 do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=opts.ssl_ciphers) 376 return "SSL", ssl_sock, host_port 377 365 378 def parse_bind_tcp(bind_tcp): 366 379 tcp_sockets = set() 367 380 if bind_tcp: … … 911 924 return show_encoding_help(opts) 912 925 913 926 bind_tcp = parse_bind_tcp(opts.bind_tcp) 927 bind_ssl = parse_bind_tcp(opts.bind_ssl) 914 928 bind_vsock = parse_bind_vsock(opts.bind_vsock) 915 929 916 930 assert mode in ("start", "start-desktop", "upgrade", "shadow", "proxy") … … 1050 1064 rec = "tcp", [(host, iport)] 1051 1065 mdns_recs.append(rec) 1052 1066 1067 for host, iport in bind_ssl: 1068 socket = setup_ssl_socket(opts, host, iport) 1069 sockets.append(socket) 1070 if opts.mdns: 1071 rec = "ssl", [(host, iport)] 1072 mdns_recs.append(rec) 1073 1053 1074 for cid, iport in bind_vsock: 1054 1075 socket = setup_vsock_socket(cid, iport) 1055 1076 sockets.append(socket) -
xpra/server/proxy/proxy_server.py
186 186 disp_desc = parse_display_name(parse_error, opts, display) 187 187 log("display description(%s) = %s", display, disp_desc) 188 188 try: 189 server_conn = connect_to(disp_desc )189 server_conn = connect_to(disp_desc, opts) 190 190 except Exception as e: 191 191 log("cannot connect", exc_info=True) 192 192 log.error("Error: cannot start proxy connection:") -
xpra/server/server_core.py
536 536 #that we need to handle via a tcp proxy or the websockify adapter: 537 537 sock.settimeout(25) 538 538 v = conn.peek(128) 539 netlog("peek( )=%s", nonl(v))539 netlog("peek(128)=%s", binascii.hexlify(v or "")) 540 540 if v and v[0] not in ("P", ord("P")): 541 541 if self._html: 542 542 line1 = v.splitlines()[0] … … 560 560 return True 561 561 else: 562 562 v = conn.peek(128) 563 netlog("%s.peek(128)=%s", conn, v)563 netlog("%s.peek(128)=%s", conn, binascii.hexlify(v or "")) 564 564 if v and v[0] not in ("P", ord("P")): 565 565 #not an xpra client 566 566 netlog("new %s connection is not an xpra client, disconnecting it", socktype)