commit e234f31d8c1017672a2000925a0e8ff4f32feda8 Author: David Fifield david@bamsoftware.com Date: Thu Jul 11 15:26:51 2013 -0700
Check every certificate's public key, not only the leaf's.
I put the Chromium kSPKIHash_Google1024 as the only allowed key, as that's the one I see right now. --- facilitator/facilitator-email-poller | 29 +++++++++++++++++------------ flashproxy-reg-appspot | 32 +++++++++++++++++--------------- flashproxy-reg-email | 24 +++++++++++++++++------- 3 files changed, 51 insertions(+), 34 deletions(-)
diff --git a/facilitator/facilitator-email-poller b/facilitator/facilitator-email-poller index a2b5cd6..8b9f10a 100755 --- a/facilitator/facilitator-email-poller +++ b/facilitator/facilitator-email-poller @@ -64,9 +64,11 @@ A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y # 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 = tuple(x.decode("hex") for x in ( - "63c445c009328b663cdff9cb68f6c523ac7b6c2b", -)) +PUBKEY_SHA1 = ( + # https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security... + # kSPKIHash_Google1024 + "\x40\xc5\x40\x1d\x6f\x8c\xba\xf0\x8b\x00\xed\xef\xb1\xee\x87\xd0\x05\xb3\xb9\xcd", +)
LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
@@ -362,15 +364,18 @@ def imap_login(): finally: ca_certs_file.close()
- # Check that the public key is what we expect. - cert = imap.ssl().get_peer_cert() - pubkey_der = cert.get_pubkey().as_der() - pubkey_digest = sha1(pubkey_der).digest() - - if options.use_certificate_pin and pubkey_digest not in PUBKEY_SHA1: - expected = "(" + ", ".join(x.encode("hex") for x in PUBKEY_SHA1) + ")" - raise ValueError("Public key does not match pin: got %s but expected any of %s" % - (pubkey_digest.encode("hex"), expected)) + if options.use_certificate_pin: + found = [] + for cert in imap.ssl().get_peer_cert_chain(): + pubkey_der = cert.get_pubkey().as_der() + pubkey_digest = sha1(pubkey_der).digest() + if pubkey_digest in 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) + ")" + raise ValueError("Public key does not match pin: got %s but expected any of %s" % (found, expected))
log(u"logging in as %s" % options.email_addr) imap.login(options.email_addr, email_password) diff --git a/flashproxy-reg-appspot b/flashproxy-reg-appspot index fc960e9..2ca3467 100755 --- a/flashproxy-reg-appspot +++ b/flashproxy-reg-appspot @@ -63,12 +63,11 @@ A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y # 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 = tuple(x.decode("hex") for x in ( - "c70ccd442ff4528c603aefef85206fd693990e09", - "1697e17a8a3317f031721b7b6293cd50643bbbd3", - "291e750bafedac444486327e50f26f64d840991a", - "1e3f66cfa0eb03136297fdb238ad6619c30ff375", -)) +PUBKEY_SHA1 = ( + # https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security... + # kSPKIHash_Google1024 + "\x40\xc5\x40\x1d\x6f\x8c\xba\xf0\x8b\x00\xed\xef\xb1\xee\x87\xd0\x05\xb3\xb9\xcd", +)
class options(object): address_family = socket.AF_UNSPEC @@ -234,15 +233,18 @@ class PinHTTPSConnection(httplib.HTTPSConnection): self.sock = SSL.Connection(ctx, sock) self.sock.connect((self.host, self.port))
- # Check that the public key is what we expect. - cert = self.sock.get_peer_cert() - pubkey_der = cert.get_pubkey().as_der() - pubkey_digest = sha1(pubkey_der).digest() - - if options.use_certificate_pin and pubkey_digest not in PUBKEY_SHA1: - expected = "(" + ", ".join(x.encode("hex") for x in PUBKEY_SHA1) + ")" - raise ValueError("Public key does not match pin: got %s but expected any of %s" % - (pubkey_digest.encode("hex"), expected)) + 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 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) + ")" + raise ValueError("Public key does not match pin: got %s but expected any of %s" % (found, expected))
class PinHTTPSHandler(urllib2.HTTPSHandler): def https_open(self, req): diff --git a/flashproxy-reg-email b/flashproxy-reg-email index a3c27ad..6d3f092 100755 --- a/flashproxy-reg-email +++ b/flashproxy-reg-email @@ -60,9 +60,11 @@ A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y # 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 = tuple(x.decode("hex") for x in ( - "69ba4a72fc198b2203ecdf0c75493e4d5300dac9", -)) +PUBKEY_SHA1 = ( + # https://src.chromium.org/viewvc/chrome/trunk/src/net/http/transport_security... + # 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 @@ -284,10 +286,18 @@ try: smtp.sock.connect_ssl() smtp.file = smtp.sock.makefile()
- # Check that the public key is what we expect. - cert = smtp.sock.get_peer_cert() - pubkey_der = cert.get_pubkey().as_der() - pubkey_digest = sha1(pubkey_der).digest() + 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 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) + ")" + 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) + ")"
tor-commits@lists.torproject.org