aboutsummaryrefslogtreecommitdiff
path: root/scripts/rpki/https.py
blob: 4be205378126334f40838f75613199c69588d79c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# $Id$

import httplib, BaseHTTPServer, tlslite.api, glob, rpki.x509

"""
HTTPS utilities, both client and server.

At the moment this only knows how to use the PEM certs in my
subversion repository; generalizing it would not be hard, but the more
general version should use SQL anyway.
"""

rpki_content_type = "application/x-rpki"

class CertInfo(object):

  cert_dir = "biz-certs/"

  def __init__(self, myname=None):

    if myname is not None:

      f = open(self.cert_dir + myname + "-EE.key", "r")
      self.privateKey = tlslite.api.parsePEMKey(f.read(), private=True)
      f.close()
      
      chain = rpki.x509.X509_chain()
      chain.load_from_PEM(glob.glob(self.cert_dir + myname + "-*.cer"))
      chain.chainsort()
      self.certChain = chain.tlslite_certChain()

      trustlist = rpki.x509.X509_chain()
      trustlist.load_from_PEM(glob.glob(self.cert_dir + "*-Root.cer"))
      self.x509TrustList = trustlist.tlslite_trustList()

def client(msg, certInfo, host="localhost", port=4433, url="/"):
  httpc = tlslite.api.HTTPTLSConnection(host=host,
                                        port=port,
                                        certChain=certInfo.certChain,
                                        privateKey=certInfo.privateKey,
                                        x509TrustList=certInfo.x509TrustList)
  httpc.connect()
  httpc.request("POST", url, msg, {"Content-Type" : rpki_content_type})
  response = httpc.getresponse()
  assert response.status == httplib.OK
  return response.read()

class requestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

  rpki_handlers = None                  # Subclass must bind

  def do_POST(self):
    assert self.headers["Content-Type"] == rpki_content_type
    query_string = self.rfile.read(int(self.headers["Content-Length"]))
    rcode = None
    try:
      handler = self.rpki_handlers[self.path]
    except KeyError:
      rcode, rtext = 404, ""
    if rcode is None:
      try:
        rcode, rtext = handler(query=query_string, path=self.path)
      except:
        rcode, rtext = 500, ""
    self.send_response(rcode)
    self.send_header("Content-Type", rpki_content_type)
    self.end_headers()
    self.wfile.write(rtext)

class httpServer(tlslite.api.TLSSocketServerMixIn, BaseHTTPServer.HTTPServer):

  rpki_certChain = None
  rpki_privateKey = None
  rpki_sessionCache = None
  
  def handshake(self, tlsConnection):
    assert self.rpki_certChain is not None
    assert self.rpki_privateKey is not None
    assert self.rpki_sessionCache is not None
    try:
      tlsConnection.handshakeServer(certChain=self.rpki_certChain,
                                    privateKey=self.rpki_privateKey,
                                    sessionCache=self.rpki_sessionCache)
      tlsConnection.ignoreAbruptClose = True
      return True
    except tlslite.api.TLSError, error:
      print "TLS handshake failure:", str(error)
      return False

def server(handlers, certInfo, port=4433, host=""):

  # BaseHTTPServer.HTTPServer takes a class, not an instance, so
  # binding our handler requires creating a new subclass.  Weird.

  class boundRequestHandler(requestHandler):
    rpki_handlers = handlers

  httpd = httpServer((host, port), boundRequestHandler)
  httpd.rpki_privateKey = certInfo.privateKey
  httpd.rpki_certChain = certInfo.certChain
  httpd.rpki_sessionCache = tlslite.api.SessionCache()

  httpd.serve_forever()