[tor-commits] [flashproxy/master] move common code into a separate flashproxy-common package

infinity0 at torproject.org infinity0 at torproject.org
Tue Nov 5 23:54:35 UTC 2013


commit aa03e11328d69aaee0caa9bf0aca9cd47673ff45
Author: Ximin Luo <infinity0 at gmx.com>
Date:   Sun Sep 15 18:28:51 2013 +0100

    move common code into a separate flashproxy-common package
---
 Makefile                  |    7 ++-
 common/.gitignore         |    5 ++
 common/flashproxy/keys.py |   54 +++++++++++++++++++++
 common/flashproxy/util.py |   52 ++++++++++++++++++++
 common/setup.py           |   22 +++++++++
 flashproxy-client         |   54 ++-------------------
 flashproxy-client-test    |   14 +++---
 flashproxy-reg-appspot    |   97 ++------------------------------------
 flashproxy-reg-email      |  115 +++------------------------------------------
 flashproxy-reg-http       |   52 +-------------------
 flashproxy-reg-url        |   64 ++-----------------------
 11 files changed, 166 insertions(+), 370 deletions(-)

diff --git a/Makefile b/Makefile
index 7aa71fc..62fd852 100644
--- a/Makefile
+++ b/Makefile
@@ -5,13 +5,14 @@ PREFIX = /usr/local
 BINDIR = $(PREFIX)/bin
 MANDIR = $(PREFIX)/share/man
 
-PYTHON = python
+PYTHON ?= PYTHONPATH=common python
 export PY2EXE_TMPDIR = py2exe-tmp
 
 CLIENT_BIN = flashproxy-client flashproxy-reg-appspot flashproxy-reg-email flashproxy-reg-http flashproxy-reg-url
 CLIENT_MAN = doc/flashproxy-client.1 doc/flashproxy-reg-appspot.1 doc/flashproxy-reg-email.1 doc/flashproxy-reg-http.1 doc/flashproxy-reg-url.1
 CLIENT_DIST_FILES = $(CLIENT_BIN) README LICENSE ChangeLog torrc
 CLIENT_DIST_DOC_FILES = $(CLIENT_MAN)
+CLIENT_DIST_LIB_COMMON = common/flashproxy/__init__.py common/flashproxy/keys.py common/flashproxy/util.py
 
 all: $(CLIENT_DIST_FILES) $(CLIENT_MAN)
 	:
@@ -34,6 +35,9 @@ dist: $(CLIENT_MAN)
 	mkdir $(DISTDIR)/doc
 	cp -f $(CLIENT_DIST_FILES) $(DISTDIR)
 	cp -f $(CLIENT_DIST_DOC_FILES) $(DISTDIR)/doc
+	test -n "$(CLIENT_DIST_LIB_COMMON)" && \
+	  { mkdir $(DISTDIR)/flashproxy && \
+	  cp -f $(CLIENT_DIST_LIB_COMMON) $(DISTDIR)/flashproxy; } || true
 	cd dist && zip -q -r -9 $(DISTNAME).zip $(DISTNAME)
 
 dist/$(DISTNAME).zip: $(CLIENT_DIST_FILES)
@@ -51,6 +55,7 @@ $(PY2EXE_TMPDIR)/dist: $(CLIENT_BIN)
 dist-exe: DISTNAME := $(DISTNAME)-win32
 dist-exe: CLIENT_BIN := $(PY2EXE_TMPDIR)/dist/*
 dist-exe: CLIENT_MAN := $(addsuffix .txt,$(CLIENT_MAN))
+dist-exe: CLIENT_DIST_LIB_COMMON := # py2exe static-links dependencies
 # Delegate to the "dist" target using the substitutions above.
 dist-exe: $(PY2EXE_TMPDIR)/dist setup.py dist
 
diff --git a/common/.gitignore b/common/.gitignore
new file mode 100644
index 0000000..b50e9ab
--- /dev/null
+++ b/common/.gitignore
@@ -0,0 +1,5 @@
+# built by setup.py
+/build
+/dist
+/MANIFEST
+/*.egg-info
diff --git a/common/flashproxy/__init__.py b/common/flashproxy/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/common/flashproxy/keys.py b/common/flashproxy/keys.py
new file mode 100644
index 0000000..71525c8
--- /dev/null
+++ b/common/flashproxy/keys.py
@@ -0,0 +1,54 @@
+# We trust no other CA certificate than this.
+#
+# To find the certificate to copy here,
+# $ strace openssl s_client -connect FRONT_DOMAIN:443 -verify 10 -CApath /etc/ssl/certs 2>&1 | grep /etc/ssl/certs
+# stat("/etc/ssl/certs/XXXXXXXX.0", {st_mode=S_IFREG|0644, st_size=YYYY, ...}) = 0
+PIN_GOOGLE_CERT = """\
+subject=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
+issuer=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+"""
+# SHA-1 digest of expected public keys. Any of these is valid. See
+# http://www.imperialviolet.org/2011/05/04/pinning.html for the reason behind
+# hashing the public key, not the entire certificate.
+PIN_GOOGLE_PUBKEY_SHA1 = (
+    # https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security_state_static.h?revision=209003&view=markup
+    # kSPKIHash_Google1024
+    "\x40\xc5\x40\x1d\x6f\x8c\xba\xf0\x8b\x00\xed\xef\xb1\xee\x87\xd0\x05\xb3\xb9\xcd",
+    # kSPKIHash_GoogleG2
+    "\x43\xda\xd6\x30\xee\x53\xf8\xa9\x80\xca\x6e\xfd\x85\xf4\x6a\xa3\x79\x90\xe0\xea",
+)
+
+# Registrations are encrypted with this public key before being emailed. Only
+# the facilitator operators should have the corresponding private key. Given a
+# private key in reg-email, get the public key like this:
+# openssl rsa -pubout < reg-email > reg-email.pub
+DEFAULT_FACILITATOR_PUBKEY_PEM = """\
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA44Mt8c599/4N2fgu6ppN
+oatPW1GOgZxxObljFtEy0OWM1eHB35OOn+Kn9MxNHTRxVWwCEi0HYxWNVs2qrXxV
+84LmWBz6A65d2qBlgltgLXusiXLrpwxVmJeO+GfmbF8ur0U9JSYxA20cGW/kujNg
+XYDGQxO1Gvxq2lHK2LQmBpkfKEE1DMFASmIvlHDQgDj3XBb5lYeOsHZmg16UrGAq
+1UH238hgJITPGLXBtwLtJkYbrATJvrEcmvI7QSm57SgYGpaB5ZdCbJL5bag5Pgt6
+M5SDDYYY4xxEPzokjFJfCQv+kcyAnzERNMQ9kR41ePTXG62bpngK5iWGeJ5XdkxG
+gwIDAQAB
+-----END PUBLIC KEY-----
+"""
diff --git a/common/flashproxy/util.py b/common/flashproxy/util.py
new file mode 100644
index 0000000..47bd87a
--- /dev/null
+++ b/common/flashproxy/util.py
@@ -0,0 +1,52 @@
+import re
+import socket
+
+def parse_addr_spec(spec, defhost = None, defport = None):
+    host = None
+    port = None
+    af = 0
+    m = None
+    # IPv6 syntax.
+    if not m:
+        m = re.match(ur'^\[(.+)\]:(\d*)$', spec)
+        if m:
+            host, port = m.groups()
+            af = socket.AF_INET6
+    if not m:
+        m = re.match(ur'^\[(.+)\]$', spec)
+        if m:
+            host, = m.groups()
+            af = socket.AF_INET6
+    # IPv4/hostname/port-only syntax.
+    if not m:
+        try:
+            host, port = spec.split(":", 1)
+        except ValueError:
+            host = spec
+        if re.match(ur'^[\d.]+$', host):
+            af = socket.AF_INET
+        else:
+            af = 0
+    host = host or defhost
+    port = port or defport
+    if port is not None:
+        port = int(port)
+    return host, port
+
+def format_addr(addr):
+    host, port = addr
+    if not host:
+        return u":%d" % port
+    # Numeric IPv6 address?
+    try:
+        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
+        af = addrs[0][0]
+    except socket.gaierror, e:
+        af = 0
+    if af == socket.AF_INET6:
+        result = u"[%s]" % host
+    else:
+        result = "%s" % host
+    if port is not None:
+        result += u":%d" % port
+    return result
diff --git a/common/setup.py b/common/setup.py
new file mode 100755
index 0000000..44c9c3e
--- /dev/null
+++ b/common/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+import sys
+
+from setuptools import setup, find_packages
+
+setup(
+    name = "flashproxy-common",
+    author = "dcf",
+    author_email = "dcf at torproject.org",
+    description = ("Common code for flashproxy"),
+    license = "BSD",
+    keywords = ['tor', 'flashproxy'],
+
+    packages = find_packages(),
+
+    version = "1.3",
+
+    install_requires = [
+        'setuptools',
+        ],
+)
diff --git a/flashproxy-client b/flashproxy-client
index cf16437..e1cfadc 100755
--- a/flashproxy-client
+++ b/flashproxy-client
@@ -20,6 +20,8 @@ import traceback
 import urllib
 import xml.sax.saxutils
 
+from flashproxy.util import parse_addr_spec, format_addr
+
 try:
     from hashlib import sha1
 except ImportError:
@@ -147,56 +149,6 @@ def log(msg):
     finally:
         log_lock.release()
 
-def parse_addr_spec(spec, defhost = None, defport = None):
-    host = None
-    port = None
-    af = 0
-    m = None
-    # IPv6 syntax.
-    if not m:
-        m = re.match(ur'^\[(.+)\]:(\d*)$', spec)
-        if m:
-            host, port = m.groups()
-            af = socket.AF_INET6
-    if not m:
-        m = re.match(ur'^\[(.+)\]$', spec)
-        if m:
-            host, = m.groups()
-            af = socket.AF_INET6
-    # IPv4/hostname/port-only syntax.
-    if not m:
-        try:
-            host, port = spec.split(":", 1)
-        except ValueError:
-            host = spec
-        if re.match(ur'^[\d.]+$', host):
-            af = socket.AF_INET
-        else:
-            af = 0
-    host = host or defhost
-    port = port or defport
-    if port is not None:
-        port = int(port)
-    return host, port
-
-def format_addr(addr):
-    host, port = addr
-    if not host:
-        return u":%d" % port
-    # Numeric IPv6 address?
-    try:
-        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
-        af = addrs[0][0]
-    except socket.gaierror, e:
-        af = 0
-    if af == socket.AF_INET6:
-        result = u"[%s]" % host
-    else:
-        result = "%s" % host
-    if port is not None:
-        result += u":%d" % port
-    return result
-
 def safe_format_addr(addr):
     return safe_str(format_addr(addr))
 
@@ -728,7 +680,7 @@ def forward_ports(pairs):
         log("%s exited with status %d." % (basename, p.returncode))
         return False
     return True
- 
+
 register_condvar = threading.Condition()
 # register_flag true means registration_thread_func should register at its next
 # opportunity.
diff --git a/flashproxy-client-test b/flashproxy-client-test
index 084a272..e3c6644 100755
--- a/flashproxy-client-test
+++ b/flashproxy-client-test
@@ -8,7 +8,7 @@ import socket
 import subprocess
 import sys
 import unittest
-
+print sys.path
 try:
     from hashlib import sha1
 except ImportError:
@@ -20,14 +20,14 @@ except ImportError:
 import imp
 dont_write_bytecode = sys.dont_write_bytecode
 sys.dont_write_bytecode = True
-flashproxy = imp.load_source("flashproxy", "flashproxy-client")
-parse_socks_request = flashproxy.parse_socks_request
-handle_websocket_request = flashproxy.handle_websocket_request
-WebSocketDecoder = flashproxy.WebSocketDecoder
-WebSocketEncoder = flashproxy.WebSocketEncoder
+fp_client = imp.load_source("fp_client", "flashproxy-client")
+parse_socks_request = fp_client.parse_socks_request
+handle_websocket_request = fp_client.handle_websocket_request
+WebSocketDecoder = fp_client.WebSocketDecoder
+WebSocketEncoder = fp_client.WebSocketEncoder
 sys.dont_write_bytecode = dont_write_bytecode
 del dont_write_bytecode
-del flashproxy
+del fp_client
 
 LOCAL_ADDRESS = ("127.0.0.1", 40000)
 REMOTE_ADDRESS = ("127.0.0.1", 40001)
diff --git a/flashproxy-reg-appspot b/flashproxy-reg-appspot
index c84f9e7..fc49985 100755
--- a/flashproxy-reg-appspot
+++ b/flashproxy-reg-appspot
@@ -13,6 +13,8 @@ import tempfile
 import urlparse
 import urllib2
 
+from flashproxy.keys import PIN_GOOGLE_CERT, PIN_GOOGLE_PUBKEY_SHA1
+from flashproxy.util import parse_addr_spec, format_addr
 from hashlib import sha1
 
 try:
@@ -32,45 +34,6 @@ TARGET_DOMAIN = "fp-reg-a.appspot.com"
 
 FLASHPROXY_REG_URL = "flashproxy-reg-url"
 
-# We trust no other CA certificate than this.
-#
-# To find the certificate to copy here,
-# $ strace openssl s_client -connect FRONT_DOMAIN:443 -verify 10 -CApath /etc/ssl/certs 2>&1 | grep /etc/ssl/certs
-# stat("/etc/ssl/certs/XXXXXXXX.0", {st_mode=S_IFREG|0644, st_size=YYYY, ...}) = 0
-CA_CERTS = """\
-subject=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
-issuer=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
-UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
-dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
-MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
-dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
-BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
-cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
-AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
-MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
-aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
-ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
-IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
-MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
-A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
-7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
-1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
------END CERTIFICATE-----
-"""
-# SHA-1 digest of expected public keys. Any of these is valid. See
-# http://www.imperialviolet.org/2011/05/04/pinning.html for the reason behind
-# hashing the public key, not the entire certificate.
-PUBKEY_SHA1 = (
-    # https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security_state_static.h?revision=209003&view=markup
-    # kSPKIHash_Google1024
-    "\x40\xc5\x40\x1d\x6f\x8c\xba\xf0\x8b\x00\xed\xef\xb1\xee\x87\xd0\x05\xb3\xb9\xcd",
-    # kSPKIHash_GoogleG2
-    "\x43\xda\xd6\x30\xee\x53\xf8\xa9\x80\xca\x6e\xfd\x85\xf4\x6a\xa3\x79\x90\xe0\xea",
-)
-
 class options(object):
     address_family = socket.AF_UNSPEC
     facilitator_pubkey_filename = None
@@ -104,56 +67,6 @@ def safe_str(s):
     else:
         return s
 
-def parse_addr_spec(spec, defhost = None, defport = None):
-    host = None
-    port = None
-    af = 0
-    m = None
-    # IPv6 syntax.
-    if not m:
-        m = re.match(ur'^\[(.+)\]:(\d*)$', spec)
-        if m:
-            host, port = m.groups()
-            af = socket.AF_INET6
-    if not m:
-        m = re.match(ur'^\[(.+)\]$', spec)
-        if m:
-            host, = m.groups()
-            af = socket.AF_INET6
-    # IPv4/hostname/port-only syntax.
-    if not m:
-        try:
-            host, port = spec.split(":", 1)
-        except ValueError:
-            host = spec
-        if re.match(ur'^[\d.]+$', host):
-            af = socket.AF_INET
-        else:
-            af = 0
-    host = host or defhost
-    port = port or defport
-    if port is not None:
-        port = int(port)
-    return host, port
-
-def format_addr(addr):
-    host, port = addr
-    if not host:
-        return u":%d" % port
-    # Numeric IPv6 address?
-    try:
-        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
-        af = addrs[0][0]
-    except socket.gaierror, e:
-        af = 0
-    if af == socket.AF_INET6:
-        result = u"[%s]" % host
-    else:
-        result = "%s" % host
-    if port is not None:
-        result += u":%d" % port
-    return result
-
 def safe_format_addr(addr):
     return safe_str(format_addr(addr))
 
@@ -225,7 +138,7 @@ class PinHTTPSConnection(httplib.HTTPSConnection):
         ca_certs_fd, ca_certs_path = tempfile.mkstemp(prefix="flashproxy-reg-appspot-",
             dir=get_state_dir(), suffix=".crt")
         try:
-            os.write(ca_certs_fd, CA_CERTS)
+            os.write(ca_certs_fd, PIN_GOOGLE_CERT)
             os.close(ca_certs_fd)
             ret = ctx.load_verify_locations(ca_certs_path)
             assert ret == 1
@@ -240,12 +153,12 @@ class PinHTTPSConnection(httplib.HTTPSConnection):
             for cert in self.sock.get_peer_cert_chain():
                 pubkey_der = cert.get_pubkey().as_der()
                 pubkey_digest = sha1(pubkey_der).digest()
-                if pubkey_digest in PUBKEY_SHA1:
+                if pubkey_digest in PIN_GOOGLE_PUBKEY_SHA1:
                     break
                 found.append(pubkey_digest)
             else:
                 found = "(" + ", ".join(x.encode("hex") for x in found) + ")"
-                expected = "(" + ", ".join(x.encode("hex") for x in PUBKEY_SHA1) + ")"
+                expected = "(" + ", ".join(x.encode("hex") for x in PIN_GOOGLE_PUBKEY_SHA1) + ")"
                 raise ValueError("Public key does not match pin: got %s but expected any of %s" % (found, expected))
 
 class PinHTTPSHandler(urllib2.HTTPSHandler):
diff --git a/flashproxy-reg-email b/flashproxy-reg-email
index 13ab5a5..0cb626b 100755
--- a/flashproxy-reg-email
+++ b/flashproxy-reg-email
@@ -10,6 +10,8 @@ import ssl
 import sys
 import tempfile
 
+from flashproxy.keys import PIN_GOOGLE_CERT, PIN_GOOGLE_PUBKEY_SHA1, DEFAULT_FACILITATOR_PUBKEY_PEM
+from flashproxy.util import parse_addr_spec, format_addr
 from hashlib import sha1
 
 try:
@@ -29,59 +31,6 @@ DEFAULT_SMTP_PORT = 25
 EHLO_FQDN = "[127.0.0.1]"
 FROM_EMAIL_ADDRESS = "nobody at localhost"
 
-# We trust no other CA certificate than this.
-#
-# To find the certificate to copy here,
-# $ strace openssl s_client -connect gmail-smtp-in.l.google.com:25 -starttls smtp -verify 10 -CApath /etc/ssl/certs 2>&1 | grep /etc/ssl/certs
-# stat("/etc/ssl/certs/XXXXXXXX.0", {st_mode=S_IFREG|0644, st_size=YYYY, ...}) = 0
-CA_CERTS = """\
-subject=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
-issuer=/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
-UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
-dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
-MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
-dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
-AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
-BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
-cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
-AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
-MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
-aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
-ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
-IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
-MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
-A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
-7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
-1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
------END CERTIFICATE-----
-"""
-# SHA-1 digest of expected public keys. Any of these is valid. See
-# http://www.imperialviolet.org/2011/05/04/pinning.html for the reason behind
-# hashing the public key, not the entire certificate.
-PUBKEY_SHA1 = (
-    # https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security_state_static.h?revision=209003&view=markup
-    # kSPKIHash_Google1024
-    "\x40\xc5\x40\x1d\x6f\x8c\xba\xf0\x8b\x00\xed\xef\xb1\xee\x87\xd0\x05\xb3\xb9\xcd",
-)
-
-# Registrations are encrypted with this public key before being emailed. Only
-# the facilitator operators should have the corresponding private key. Given a
-# private key in reg-email, get the public key like this:
-# openssl rsa -pubout < reg-email > reg-email.pub
-DEFAULT_FACILITATOR_PUBKEY_PEM = """\
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA44Mt8c599/4N2fgu6ppN
-oatPW1GOgZxxObljFtEy0OWM1eHB35OOn+Kn9MxNHTRxVWwCEi0HYxWNVs2qrXxV
-84LmWBz6A65d2qBlgltgLXusiXLrpwxVmJeO+GfmbF8ur0U9JSYxA20cGW/kujNg
-XYDGQxO1Gvxq2lHK2LQmBpkfKEE1DMFASmIvlHDQgDj3XBb5lYeOsHZmg16UrGAq
-1UH238hgJITPGLXBtwLtJkYbrATJvrEcmvI7QSm57SgYGpaB5ZdCbJL5bag5Pgt6
-M5SDDYYY4xxEPzokjFJfCQv+kcyAnzERNMQ9kR41ePTXG62bpngK5iWGeJ5XdkxG
-gwIDAQAB
------END PUBLIC KEY-----
-"""
-
 class options(object):
     remote_addr = None
     email_addr = None
@@ -131,56 +80,6 @@ def safe_str(s):
     else:
         return s
 
-def parse_addr_spec(spec, defhost = None, defport = None):
-    host = None
-    port = None
-    af = 0
-    m = None
-    # IPv6 syntax.
-    if not m:
-        m = re.match(ur'^\[(.+)\]:(\d*)$', spec)
-        if m:
-            host, port = m.groups()
-            af = socket.AF_INET6
-    if not m:
-        m = re.match(ur'^\[(.+)\]$', spec)
-        if m:
-            host, = m.groups()
-            af = socket.AF_INET6
-    # IPv4/hostname/port-only syntax.
-    if not m:
-        try:
-            host, port = spec.split(":", 1)
-        except ValueError:
-            host = spec
-        if re.match(ur'^[\d.]+$', host):
-            af = socket.AF_INET
-        else:
-            af = 0
-    host = host or defhost
-    port = port or defport
-    if port is not None:
-        port = int(port)
-    return host, port
-
-def format_addr(addr):
-    host, port = addr
-    if not host:
-        return u":%d" % port
-    # Numeric IPv6 address?
-    try:
-        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
-        af = addrs[0][0]
-    except socket.gaierror, e:
-        af = 0
-    if af == socket.AF_INET6:
-        result = u"[%s]" % host
-    else:
-        result = "%s" % host
-    if port is not None:
-        result += u":%d" % port
-    return result
-
 def safe_format_addr(addr):
     return safe_str(format_addr(addr))
 
@@ -265,7 +164,7 @@ try:
     ca_certs_fd, ca_certs_path = tempfile.mkstemp(prefix="flashproxy-reg-email-",
         dir=get_state_dir(), suffix=".crt")
     try:
-        os.write(ca_certs_fd, CA_CERTS)
+        os.write(ca_certs_fd, PIN_GOOGLE_CERT)
         os.close(ca_certs_fd)
         # We roll our own initial EHLO/STARTTLS because smtplib.SMTP.starttls
         # doesn't allow enough certificate validation.
@@ -291,16 +190,16 @@ try:
         for cert in smtp.sock.get_peer_cert_chain():
             pubkey_der = cert.get_pubkey().as_der()
             pubkey_digest = sha1(pubkey_der).digest()
-            if pubkey_digest in PUBKEY_SHA1:
+            if pubkey_digest in PIN_GOOGLE_PUBKEY_SHA1:
                 break
             found.append(pubkey_digest)
         else:
             found = "(" + ", ".join(x.encode("hex") for x in found) + ")"
-            expected = "(" + ", ".join(x.encode("hex") for x in PUBKEY_SHA1) + ")"
+            expected = "(" + ", ".join(x.encode("hex") for x in PIN_GOOGLE_PUBKEY_SHA1) + ")"
             raise ValueError("Public key does not match pin: got %s but expected any of %s" % (found, expected))
 
-    if options.use_certificate_pin and pubkey_digest not in PUBKEY_SHA1:
-        expected = "(" + ", ".join(x.encode("hex") for x in PUBKEY_SHA1) + ")"
+    if options.use_certificate_pin and pubkey_digest not in PIN_GOOGLE_PUBKEY_SHA1:
+        expected = "(" + ", ".join(x.encode("hex") for x in PIN_GOOGLE_PUBKEY_SHA1) + ")"
         raise ValueError("Public key does not match pin: got %s but expected any of %s" %
             (pubkey_digest.encode("hex"), expected))
 
diff --git a/flashproxy-reg-http b/flashproxy-reg-http
index 975ebda..6639e57 100755
--- a/flashproxy-reg-http
+++ b/flashproxy-reg-http
@@ -8,6 +8,8 @@ import sys
 import urllib
 import urllib2
 
+from flashproxy.util import parse_addr_spec, format_addr
+
 DEFAULT_REMOTE_ADDRESS = ""
 DEFAULT_REMOTE_PORT = 9000
 DEFAULT_FACILITATOR_URL = "https://fp-facilitator.org/"
@@ -43,56 +45,6 @@ def safe_str(s):
     else:
         return s
 
-def parse_addr_spec(spec, defhost = None, defport = None):
-    host = None
-    port = None
-    af = 0
-    m = None
-    # IPv6 syntax.
-    if not m:
-        m = re.match(ur'^\[(.+)\]:(\d*)$', spec)
-        if m:
-            host, port = m.groups()
-            af = socket.AF_INET6
-    if not m:
-        m = re.match(ur'^\[(.+)\]$', spec)
-        if m:
-            host, = m.groups()
-            af = socket.AF_INET6
-    # IPv4/hostname/port-only syntax.
-    if not m:
-        try:
-            host, port = spec.split(":", 1)
-        except ValueError:
-            host = spec
-        if re.match(ur'^[\d.]+$', host):
-            af = socket.AF_INET
-        else:
-            af = 0
-    host = host or defhost
-    port = port or defport
-    if port is not None:
-        port = int(port)
-    return host, port
-
-def format_addr(addr):
-    host, port = addr
-    if not host:
-        return u":%d" % port
-    # Numeric IPv6 address?
-    try:
-        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
-        af = addrs[0][0]
-    except socket.gaierror, e:
-        af = 0
-    if af == socket.AF_INET6:
-        result = u"[%s]" % host
-    else:
-        result = "%s" % host
-    if port is not None:
-        result += u":%d" % port
-    return result
-
 options.facilitator_url = DEFAULT_FACILITATOR_URL
 options.remote_addr = (DEFAULT_REMOTE_ADDRESS, DEFAULT_REMOTE_PORT)
 
diff --git a/flashproxy-reg-url b/flashproxy-reg-url
index b30c550..1c0b348 100755
--- a/flashproxy-reg-url
+++ b/flashproxy-reg-url
@@ -7,6 +7,9 @@ import socket
 import sys
 import urlparse
 
+from flashproxy.keys import DEFAULT_FACILITATOR_PUBKEY_PEM
+from flashproxy.util import parse_addr_spec, format_addr
+
 try:
     from M2Crypto import BIO, RSA
 except ImportError:
@@ -16,17 +19,6 @@ except ImportError:
 DEFAULT_REMOTE_ADDRESS = None
 DEFAULT_REMOTE_PORT = 9000
 DEFAULT_FACILITATOR_URL = "https://fp-facilitator.org/"
-DEFAULT_FACILITATOR_PUBKEY_PEM = """\
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA44Mt8c599/4N2fgu6ppN
-oatPW1GOgZxxObljFtEy0OWM1eHB35OOn+Kn9MxNHTRxVWwCEi0HYxWNVs2qrXxV
-84LmWBz6A65d2qBlgltgLXusiXLrpwxVmJeO+GfmbF8ur0U9JSYxA20cGW/kujNg
-XYDGQxO1Gvxq2lHK2LQmBpkfKEE1DMFASmIvlHDQgDj3XBb5lYeOsHZmg16UrGAq
-1UH238hgJITPGLXBtwLtJkYbrATJvrEcmvI7QSm57SgYGpaB5ZdCbJL5bag5Pgt6
-M5SDDYYY4xxEPzokjFJfCQv+kcyAnzERNMQ9kR41ePTXG62bpngK5iWGeJ5XdkxG
-gwIDAQAB
------END PUBLIC KEY-----
-"""
 
 class options(object):
     facilitator_url = None
@@ -51,56 +43,6 @@ default PORT is %(port)d.
     "port": DEFAULT_REMOTE_PORT,
 }
 
-def parse_addr_spec(spec, defhost = None, defport = None):
-    host = None
-    port = None
-    af = 0
-    m = None
-    # IPv6 syntax.
-    if not m:
-        m = re.match(ur'^\[(.+)\]:(\d*)$', spec)
-        if m:
-            host, port = m.groups()
-            af = socket.AF_INET6
-    if not m:
-        m = re.match(ur'^\[(.+)\]$', spec)
-        if m:
-            host, = m.groups()
-            af = socket.AF_INET6
-    # IPv4/hostname/port-only syntax.
-    if not m:
-        try:
-            host, port = spec.split(":", 1)
-        except ValueError:
-            host = spec
-        if re.match(ur'^[\d.]+$', host):
-            af = socket.AF_INET
-        else:
-            af = 0
-    host = host or defhost
-    port = port or defport
-    if port is not None:
-        port = int(port)
-    return host, port
-
-def format_addr(addr):
-    host, port = addr
-    if not host:
-        return u":%d" % port
-    # Numeric IPv6 address?
-    try:
-        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
-        af = addrs[0][0]
-    except socket.gaierror, e:
-        af = 0
-    if af == socket.AF_INET6:
-        result = u"[%s]" % host
-    else:
-        result = "%s" % host
-    if port is not None:
-        result += u":%d" % port
-    return result
-
 def get_facilitator_pubkey():
     if options.facilitator_pubkey_filename is not None:
         return RSA.load_pub_key(options.facilitator_pubkey_filename)





More information about the tor-commits mailing list