adding SSL Encryption to all WebInterface Ports with Python OpenSSL
authorRico Schulte <ricoschulte@users.schwerkraft.elitedvb.net>
Wed, 2 Jul 2008 18:53:04 +0000 (18:53 +0000)
committerRico Schulte <ricoschulte@users.schwerkraft.elitedvb.net>
Wed, 2 Jul 2008 18:53:04 +0000 (18:53 +0000)
Its now possible to switch on SSL Encryption for each Port configured in the WebIf
As this is not a official selfsigning SSL Certificate, the Browsers aka Clients have to define an exception for this.
PLEASE NOTE: The Use of a public Private Key isnt secure. To make it secure, you have to generate your own selfsigning certifikate!
The Server Keys server.pem and the certificate cacert.pem are stored in the folder /etc/enigma2/ to have it in Backup Files

webinterface/CONTROL/control
webinterface/Makefile.am
webinterface/etc/Makefile.am [new file with mode: 0644]
webinterface/etc/cacert.pem [new file with mode: 0644]
webinterface/etc/server.pem [new file with mode: 0644]
webinterface/src/WebIfConfig.py
webinterface/src/__init__.py
webinterface/src/plugin.py

index 02100a7..c0fac9f 100644 (file)
@@ -6,4 +6,4 @@ Priority: optional
 Maintainer: Felix Domke <tmbinc@elitedvb.net>
 Architecture: noarch
 Homepage: unknown
-Depends: enigma2(>2.3cvs20071008), twisted-web2
+Depends: enigma2(>2.3cvs20071008), twisted-web2, python-pyopenssl
index a00082d..e8f3375 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = src
+SUBDIRS = src etc
 
 PWD=$(shell pwd)
 
diff --git a/webinterface/etc/Makefile.am b/webinterface/etc/Makefile.am
new file mode 100644 (file)
index 0000000..63db133
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = /etc/enigma2\r
+\r
+install_DATA = server.pem cacert.pem\r
diff --git a/webinterface/etc/cacert.pem b/webinterface/etc/cacert.pem
new file mode 100644 (file)
index 0000000..5f72514
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICUzCCAbwCCQDvZPqGCXR4YDANBgkqhkiG9w0BAQUFADBuMQswCQYDVQQGEwIw
+MDERMA8GA1UECBMISW50ZXJuZXQxEDAOBgNVBAcTB0VuaWdtYTIxFTATBgNVBAoT
+DFdlYmludGVyZmFjZTEQMA4GA1UECxMHdHdpc3RlZDERMA8GA1UEAxMIRHJlYW1i
+b3gwHhcNMDgwNzAxMTgzMDMxWhcNMzUxMTE2MTgzMDMxWjBuMQswCQYDVQQGEwIw
+MDERMA8GA1UECBMISW50ZXJuZXQxEDAOBgNVBAcTB0VuaWdtYTIxFTATBgNVBAoT
+DFdlYmludGVyZmFjZTEQMA4GA1UECxMHdHdpc3RlZDERMA8GA1UEAxMIRHJlYW1i
+b3gwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL7fil+4R/gNy++UEJHvRcB/
+j2iUpuB3iLDNY8dK4KAzIVzelWmWTZDvQMIu36pokSS4iXGMQCKum2gJLpq9pdAq
+WShEHWPJTbzhRtiW5Ts9vjNW7FAW86rE2AKBeiWqe+Idd4xtPfjKqhgW1lV9b1TG
+E9USZ5g9bDx5A43hqo6NAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAhCjWqtIbJ/9c
+ITmR3fJG1zJUD83bhQqRerXMdzpb7kQ1yksXxF4IZKOwf4SRLrKZDByzBfepMEyw
+ULP7E3lkSV+5L03C+Szj6GR+1oqXd9F4y6L1skdfz2jQWcCLAFjYzH6o+DeGW7TQ
+l/l+zpWEnqbCZyZrWnMMHDV9UbkBeW4=
+-----END CERTIFICATE-----
diff --git a/webinterface/etc/server.pem b/webinterface/etc/server.pem
new file mode 100644 (file)
index 0000000..92ff59c
--- /dev/null
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQC+34pfuEf4DcvvlBCR70XAf49olKbgd4iwzWPHSuCgMyFc3pVp
+lk2Q70DCLt+qaJEkuIlxjEAirptoCS6avaXQKlkoRB1jyU284UbYluU7Pb4zVuxQ
+FvOqxNgCgXolqnviHXeMbT34yqoYFtZVfW9UxhPVEmeYPWw8eQON4aqOjQIDAQAB
+AoGBAKFieKj+Mzu0zp2+31PEr4FXWXXfWkmoR9bVkmvLD6nkEW1odYRVJThKUsLc
+xxhaWX5m2S88mm24nIWWXeVQPIUTJf4vmASUMTypT0HrJia43DcLXW2UvVQShlvj
+S/LDzbXZ5BkqYegqvypWX6DXzgNeAVEkhWJfqfvC+Gclxr+BAkEA6bwzgN+851xi
+6Qn8JQ5dZMnmjbp6bDZm5bJk5sKU4fbbu3POujpEPKDW3X8Gx1gJ9hI8zn9jSciK
+eSAquyjZ9QJBANEOHrRRRs4t9gmzlB9O9TXgGh3K9BfUkHiN+mbrR+Z5HcezHkNT
+v2+2xk7cYj88CKepadExCmgPapudyGQSizkCQQC4yCujb74k3jnn6Bfpp8CX5LIb
+S9hq4ltYrj7s29neBk3SlQxS16uIjtMvCrRuNiCx49skmTsCYsNuXMrLadFdAkB2
+kV2Uw6w28BZldjaCc1PcFJh7YUqD4Yl29n+Ys8T50KO1Sb/WS7996toajCAk4TW/
+cfSUMw5F6sh6LkkjiOjxAkAjSydPd/yKoiE8t2urn6xC8duJ1lbk/ck3/Nvyqw9y
+HRc4afanRzhmVBStHFD4yc0NyOIHwC6cJ941aNMR9XCP
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICUzCCAbwCCQDvZPqGCXR4YDANBgkqhkiG9w0BAQUFADBuMQswCQYDVQQGEwIw
+MDERMA8GA1UECBMISW50ZXJuZXQxEDAOBgNVBAcTB0VuaWdtYTIxFTATBgNVBAoT
+DFdlYmludGVyZmFjZTEQMA4GA1UECxMHdHdpc3RlZDERMA8GA1UEAxMIRHJlYW1i
+b3gwHhcNMDgwNzAxMTgzMDMxWhcNMzUxMTE2MTgzMDMxWjBuMQswCQYDVQQGEwIw
+MDERMA8GA1UECBMISW50ZXJuZXQxEDAOBgNVBAcTB0VuaWdtYTIxFTATBgNVBAoT
+DFdlYmludGVyZmFjZTEQMA4GA1UECxMHdHdpc3RlZDERMA8GA1UEAxMIRHJlYW1i
+b3gwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL7fil+4R/gNy++UEJHvRcB/
+j2iUpuB3iLDNY8dK4KAzIVzelWmWTZDvQMIu36pokSS4iXGMQCKum2gJLpq9pdAq
+WShEHWPJTbzhRtiW5Ts9vjNW7FAW86rE2AKBeiWqe+Idd4xtPfjKqhgW1lV9b1TG
+E9USZ5g9bDx5A43hqo6NAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAhCjWqtIbJ/9c
+ITmR3fJG1zJUD83bhQqRerXMdzpb7kQ1yksXxF4IZKOwf4SRLrKZDByzBfepMEyw
+ULP7E3lkSV+5L03C+Szj6GR+1oqXd9F4y6L1skdfz2jQWcCLAFjYzH6o+DeGW7TQ
+l/l+zpWEnqbCZyZrWnMMHDV9UbkBeW4=
+-----END CERTIFICATE-----
index b757640..aa09b01 100644 (file)
@@ -211,6 +211,7 @@ class WebIfInterfaceConfigScreen(Screen, ConfigListScreen):
         cfglist.append(getConfigListEntry(_("Adress"), current.adress))
         cfglist.append(getConfigListEntry(_("Port"), current.port))
         cfglist.append(getConfigListEntry(_("use Authorization"), current.useauth))
+        cfglist.append(getConfigListEntry(_("use SSL Encryption"), current.usessl))
         ConfigListScreen.__init__(self, cfglist, session)
         self.ifacenum = i
 
index 957bf88..a746abe 100644 (file)
@@ -21,6 +21,7 @@ config.plugins.Webinterface.loadmovielength = ConfigYesNo(default = False)
 config.plugins.Webinterface.version = ConfigText(__version__) # used to make the versioninfo accessible enigma2-wide, not confgurable in GUI. 
 config.plugins.Webinterface.interfacecount = ConfigInteger(0)
 config.plugins.Webinterface.interfaces = ConfigSubList()
+config.plugins.Webinterface.warningsslsend = ConfigYesNo(default = False)
 
 
 def addInterfaceConfig():
@@ -31,6 +32,7 @@ def addInterfaceConfig():
     config.plugins.Webinterface.interfaces[i].adress = ConfigSelection(choices,default=choices[0])
     config.plugins.Webinterface.interfaces[i].port = ConfigInteger(80, (0,65535))
     config.plugins.Webinterface.interfaces[i].useauth = ConfigYesNo(default = False)
+    config.plugins.Webinterface.interfaces[i].usessl = ConfigYesNo(default = False)
     config.plugins.Webinterface.interfacecount.value = i+1
     return i
 
@@ -54,6 +56,7 @@ if config.plugins.Webinterface.interfacecount.value == 0:
     config.plugins.Webinterface.interfaces[0].adress = ConfigSelection(getCofiguredAndSpecialNetworkinterfaces(),default='0.0.0.0')
     config.plugins.Webinterface.interfaces[0].port = ConfigInteger(80, (0,65535))
     config.plugins.Webinterface.interfaces[0].useauth = ConfigYesNo(default = False)
+    config.plugins.Webinterface.interfaces[0].usessl = ConfigYesNo(default = False)
     config.plugins.Webinterface.interfacecount.value = 1
     config.plugins.Webinterface.interfacecount.save()
     config.plugins.Webinterface.interfaces[0].save()
index 6e48b88..97d2fdf 100644 (file)
@@ -13,6 +13,9 @@ from twisted.cred.portal import Portal, IRealm
 from twisted.cred import checkers, credentials, error
 from zope.interface import Interface, implements
 from socket import gethostname as socket_gethostname
+from OpenSSL import SSL
+from twisted.internet import reactor, defer, ssl
+
 DEBUG_TO_FILE=False # PLEASE DONT ENABLE LOGGING BY DEFAULT (OR COMMIT TO PLUGIN CVS)
 
 DEBUGFILE= "/tmp/twisted.log"
@@ -77,11 +80,11 @@ def startWebserver(session):
        for i in range(0, config.plugins.Webinterface.interfacecount.value):
                c = config.plugins.Webinterface.interfaces[i]
                if c.disabled.value is False:
-                       startServerInstance(session,c.adress.value,c.port.value,c.useauth.value)
+                       startServerInstance(session,c.adress.value,c.port.value,c.useauth.value,c.usessl.value)
                else:
                        print "[Webinterface] not starting disabled interface on %s:%i"%(c.adress.value,c.port.value)
                        
-def startServerInstance(session,ipadress,port,useauth=False):
+def startServerInstance(session,ipadress,port,useauth=False,usessl=False):
        try:
                toplevel = Toplevel(session)
                if useauth:
@@ -92,13 +95,19 @@ def startServerInstance(session,ipadress,port,useauth=False):
                else:
                        site = server.Site(toplevel)
                try:
-                       d = reactor.listenTCP(port, channel.HTTPFactory(site),interface=ipadress)
+                       #########
+                       if usessl:                              
+                               ctx = ssl.DefaultOpenSSLContextFactory('/etc/enigma2/server.pem','/etc/enigma2/cacert.pem',sslmethod=SSL.SSLv23_METHOD)
+                               d = reactor.listenSSL(port, channel.HTTPFactory(site),ctx,interface=ipadress)
+                       else:
+                               d = reactor.listenTCP(port, channel.HTTPFactory(site),interface=ipadress)
                        running_defered.append(d)
-                       print "[Webinterface] started on %s:%i"%(ipadress,port),"auth=",useauth
+                       print "[Webinterface] started on %s:%i"%(ipadress,port),"auth=",useauth,"ssl=",usessl
                except CannotListenError, e:
                        print "[Webinterface] Could not Listen on %s:%i!"%(ipadress,port)
                        session.open(MessageBox,'Could not Listen on %s:%i!\n\n%s'%(ipadress,port,str(e)), MessageBox.TYPE_ERROR)
-       except Exception,e:
+#      except Exception,e:
+       except CannotListenError,e:
                print "[Webinterface] starting FAILED on %s:%i!"%(ipadress,port),e
                session.open(MessageBox,'starting FAILED on %s:%i!\n\n%s'%(ipadress,port,str(e)), MessageBox.TYPE_ERROR)
 
@@ -302,4 +311,64 @@ def passcrypt_md5(passwd, salt=None, magic='$1$'):
     
     return rv
 
+#### stuff for SSL Support
+def makeSSLContext(myKey,trustedCA):
+     '''Returns an ssl Context Object
+    @param myKey a pem formated key and certifcate with for my current host
+           the other end of this connection must have the cert from the CA
+           that signed this key
+    @param trustedCA a pem formated certificat from a CA you trust
+           you will only allow connections from clients signed by this CA
+           and you will only allow connections to a server signed by this CA
+     '''
+
+     # our goal in here is to make a SSLContext object to pass to connectSSL
+     # or listenSSL
+
+     # Why these functioins... Not sure...
+     fd = open(myKey,'r')
+     ss = fd.read()
+     theCert = ssl.PrivateCertificate.loadPEM(ss)
+     fd.close()
+     fd = open(trustedCA,'r')
+     theCA = ssl.Certificate.loadPEM(fd.read())
+     fd.close()
+     #ctx = theCert.options(theCA)
+     ctx = theCert.options()
+
+     # Now the options you can set look like Standard OpenSSL Library options
+
+     # The SSL protocol to use, one of SSLv23_METHOD, SSLv2_METHOD,
+     # SSLv3_METHOD, TLSv1_METHOD. Defaults to TLSv1_METHOD.
+     ctx.method = ssl.SSL.TLSv1_METHOD
+
+     # If True, verify certificates received from the peer and fail
+     # the handshake if verification fails. Otherwise, allow anonymous
+     # sessions and sessions with certificates which fail validation.
+     ctx.verify = True
+
+     # Depth in certificate chain down to which to verify.
+     ctx.verifyDepth = 1
+
+     # If True, do not allow anonymous sessions.
+     ctx.requireCertification = True
+
+     # If True, do not re-verify the certificate on session resumption.
+     ctx.verifyOnce = True
+
+     # If True, generate a new key whenever ephemeral DH parameters are used
+     # to prevent small subgroup attacks.
+     ctx.enableSingleUseKeys = True
+
+     # If True, set a session ID on each context. This allows a shortened
+     # handshake to be used when a known client reconnects.
+     ctx.enableSessions = True
+
+     # If True, enable various non-spec protocol fixes for broken
+     # SSL implementations.
+     ctx.fixBrokenPeers = False
+
+     return ctx
+
+