[tor-commits] [flashproxy/master] factor out certificate checking and pinning into flashproxy.keys
infinity0 at torproject.org
infinity0 at torproject.org
Wed Nov 6 21:34:32 UTC 2013
commit 1e541947c32f8d390b5df1cc1c42928e7c058dd5
Author: Ximin Luo <infinity0 at gmx.com>
Date: Wed Nov 6 17:32:21 2013 +0000
factor out certificate checking and pinning into flashproxy.keys
---
Makefile | 2 +-
flashproxy-reg-appspot | 25 ++++---------------------
flashproxy-reg-email | 31 ++++---------------------------
flashproxy/keys.py | 31 +++++++++++++++++++++++++++++++
flashproxy/test/test_keys.py | 22 ++++++++++++++++++++++
setup-common.py | 3 ++-
6 files changed, 64 insertions(+), 50 deletions(-)
diff --git a/Makefile b/Makefile
index 2429f33..5623c4f 100644
--- a/Makefile
+++ b/Makefile
@@ -77,7 +77,7 @@ distclean:
test: check
check:
$(MAKE_CLIENT) check
- $(PYTHON) setup-common.py check
+ $(PYTHON) setup-common.py test
cd facilitator && ./facilitator-test
cd proxy && ./flashproxy-test.js
diff --git a/flashproxy-reg-appspot b/flashproxy-reg-appspot
index c47579c..a261f10 100755
--- a/flashproxy-reg-appspot
+++ b/flashproxy-reg-appspot
@@ -13,9 +13,8 @@ import tempfile
import urlparse
import urllib2
-from flashproxy.keys import PIN_GOOGLE_CERT, PIN_GOOGLE_PUBKEY_SHA1
+from flashproxy.keys import PIN_GOOGLE_CERT, PIN_GOOGLE_PUBKEY_SHA1, check_certificate_pin, temp_cert
from flashproxy.util import parse_addr_spec, format_addr
-from hashlib import sha1
try:
from M2Crypto import SSL, X509
@@ -142,31 +141,15 @@ class PinHTTPSConnection(httplib.HTTPSConnection):
ctx = SSL.Context("tlsv1")
ctx.set_verify(SSL.verify_peer, 3)
- ca_certs_fd, ca_certs_path = tempfile.mkstemp(prefix="flashproxy-reg-appspot-",
- dir=get_state_dir(), suffix=".crt")
- try:
- os.write(ca_certs_fd, PIN_GOOGLE_CERT)
- os.close(ca_certs_fd)
- ret = ctx.load_verify_locations(ca_certs_path)
+ with temp_cert(PIN_GOOGLE_CERT) as ca_file:
+ ret = ctx.load_verify_locations(ca_file.name)
assert ret == 1
- finally:
- os.unlink(ca_certs_path)
self.sock = SSL.Connection(ctx, sock)
self.sock.connect((self.host, self.port))
if options.use_certificate_pin:
- found = []
- 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 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 PIN_GOOGLE_PUBKEY_SHA1) + ")"
- raise ValueError("Public key does not match pin: got %s but expected any of %s" % (found, expected))
+ check_certificate_pin(self.sock, PIN_GOOGLE_PUBKEY_SHA1)
class PinHTTPSHandler(urllib2.HTTPSHandler):
def https_open(self, req):
diff --git a/flashproxy-reg-email b/flashproxy-reg-email
index 8bc8b6f..4f4599c 100755
--- a/flashproxy-reg-email
+++ b/flashproxy-reg-email
@@ -11,9 +11,8 @@ import sys
import tempfile
import urllib
-from flashproxy.keys import PIN_GOOGLE_CERT, PIN_GOOGLE_PUBKEY_SHA1, DEFAULT_FACILITATOR_PUBKEY_PEM
+from flashproxy.keys import PIN_GOOGLE_CERT, PIN_GOOGLE_PUBKEY_SHA1, DEFAULT_FACILITATOR_PUBKEY_PEM, check_certificate_pin, temp_cert
from flashproxy.util import parse_addr_spec, format_addr
-from hashlib import sha1
try:
from M2Crypto import BIO, RSA, SSL, X509
@@ -185,11 +184,7 @@ try:
ctx = SSL.Context("tlsv1")
ctx.set_verify(SSL.verify_peer, 3)
- ca_certs_fd, ca_certs_path = tempfile.mkstemp(prefix="flashproxy-reg-email-",
- dir=get_state_dir(), suffix=".crt")
- try:
- os.write(ca_certs_fd, PIN_GOOGLE_CERT)
- os.close(ca_certs_fd)
+ with temp_cert(PIN_GOOGLE_CERT) as ca_file:
# We roll our own initial EHLO/STARTTLS because smtplib.SMTP.starttls
# doesn't allow enough certificate validation.
code, msg = smtp.docmd("EHLO", EHLO_FQDN)
@@ -198,10 +193,8 @@ try:
code, msg = smtp.docmd("STARTTLS")
if code != 220:
raise ValueError("Got code %d after STARTTLS" % code)
- ret = ctx.load_verify_locations(ca_certs_path)
+ ret = ctx.load_verify_locations(ca_file.name)
assert ret == 1
- finally:
- os.unlink(ca_certs_path)
smtp.sock = SSL.Connection(ctx, smtp.sock)
smtp.sock.setup_ssl()
@@ -210,23 +203,7 @@ try:
smtp.file = smtp.sock.makefile()
if options.use_certificate_pin:
- found = []
- 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 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 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 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))
-
+ check_certificate_pin(smtp.sock, PIN_GOOGLE_PUBKEY_SHA1)
smtp.ehlo(EHLO_FQDN)
if not options.remote_addr[0]:
diff --git a/flashproxy/keys.py b/flashproxy/keys.py
index 71525c8..5b4b9fa 100644
--- a/flashproxy/keys.py
+++ b/flashproxy/keys.py
@@ -1,3 +1,7 @@
+import tempfile
+
+from hashlib import sha1
+
# We trust no other CA certificate than this.
#
# To find the certificate to copy here,
@@ -52,3 +56,30 @@ M5SDDYYY4xxEPzokjFJfCQv+kcyAnzERNMQ9kR41ePTXG62bpngK5iWGeJ5XdkxG
gwIDAQAB
-----END PUBLIC KEY-----
"""
+
+def check_certificate_pin(sock, cert_pubkey):
+ found = []
+ for cert in sock.get_peer_cert_chain():
+ pubkey_der = cert.get_pubkey().as_der()
+ pubkey_digest = sha1(pubkey_der).digest()
+ if pubkey_digest in cert_pubkey:
+ break
+ found.append(pubkey_digest)
+ else:
+ found = "(" + ", ".join(x.encode("hex") for x in found) + ")"
+ expected = "(" + ", ".join(x.encode("hex") for x in cert_pubkey) + ")"
+ raise ValueError("Public key does not match pin: got %s but expected any of %s" % (found, expected))
+
+class temp_cert(object):
+ """Implements a with-statement over raw certificate data."""
+
+ def __init__(self, certdata):
+ self.fd = tempfile.NamedTemporaryFile(prefix="fp-cert-temp-", suffix=".crt", delete=True)
+ self.fd.write(certdata)
+ self.fd.flush()
+
+ def __enter__(self):
+ return self.fd
+
+ def __exit__(self, type, value, traceback):
+ self.fd.close()
diff --git a/flashproxy/test/__init__.py b/flashproxy/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/flashproxy/test/test_keys.py b/flashproxy/test/test_keys.py
new file mode 100644
index 0000000..de22279
--- /dev/null
+++ b/flashproxy/test/test_keys.py
@@ -0,0 +1,22 @@
+import os.path
+import unittest
+
+from flashproxy.keys import PIN_GOOGLE_CERT, PIN_GOOGLE_PUBKEY_SHA1, DEFAULT_FACILITATOR_PUBKEY_PEM, check_certificate_pin, temp_cert
+
+class TempCertTest(unittest.TestCase):
+ def test_temp_cert_success(self):
+ fn = None
+ with temp_cert(PIN_GOOGLE_CERT) as ca_file:
+ fn = ca_file.name
+ self.assertTrue(os.path.exists(fn))
+ self.assertFalse(os.path.exists(fn))
+
+ def test_temp_cert_raise(self):
+ fn = None
+ try:
+ with temp_cert(PIN_GOOGLE_CERT) as ca_file:
+ fn = ca_file.name
+ raise ValueError()
+ self.fail()
+ except ValueError:
+ self.assertFalse(os.path.exists(fn))
diff --git a/setup-common.py b/setup-common.py
index 5d98fd9..97d2099 100755
--- a/setup-common.py
+++ b/setup-common.py
@@ -32,7 +32,8 @@ setup(
license = "BSD",
keywords = ['tor', 'flashproxy'],
- packages = find_packages(),
+ packages = find_packages(exclude=['*.test']),
+ test_suite='flashproxy.test',
version = "1.4",
More information about the tor-commits
mailing list