restart tpmd on uds timeout
[enigma2-plugins.git] / genuinedreambox / src / plugin.py
1 # -*- coding: utf-8 -*-
2 ###########################################################################
3 #
4 # http://newnigma2.to
5 #
6 # $Id:
7 #
8 # Copyright (C) 2009 by
9 # <nixkoenner@newnigma2.to>
10 #
11 #       License: GPL
12 #
13 #       This program is free software; you can redistribute it and/or modify
14 #       it under the terms of the GNU General Public License as published by
15 #       the Free Software Foundation; either version 2 of the License, or
16 #       (at your option) any later version.
17 #
18 #       This program is distributed in the hope that it will be useful,
19 #       but WITHOUT ANY WARRANTY; without even the implied warranty of
20 #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 #       GNU General Public License for more details.
22 #
23 #       You should have received a copy of the GNU General Public License
24 #       along with this program; if not, write to the Free Software
25 #       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #
27 ###########################################################################
28 #
29 # thx to <kayshadow@newnigma2.to> for painting the icon 
30 #
31 from Plugins.Plugin import PluginDescriptor
32 from Screens.Screen import Screen
33
34 from Components.ActionMap import ActionMap
35 from Components.Button import Button
36 from Components.Label import Label 
37
38 import socket
39 import struct
40 import base64
41 import os
42
43 from twisted.web.client import getPage
44
45 TPMD_DT_RESERVED = 0x00
46 TPMD_DT_PROTOCOL_VERSION = 0x01
47 TPMD_DT_TPM_VERSION    = 0x02
48 TPMD_DT_SERIAL = 0x03
49 TPMD_DT_LEVEL2_CERT = 0x04
50 TPMD_DT_LEVEL3_CERT    = 0x05
51 TPMD_DT_FAB_CA_CERT    = 0x06
52 TPMD_DT_DATABLOCK_SIGNED = 0x07
53 TPMD_CMD_RESERVED    = 0x0000
54 TPMD_CMD_GET_DATA    = 0x0001
55 TPMD_CMD_APDU    = 0x0002
56 TPMD_CMD_COMPUTE_SIGNATURE = 0x0003
57
58 class genuineDreambox(Screen):
59     skin = """
60         <screen position="60,80" size="620,420" title="%s" >
61         <widget name="infotext" position="10,20" zPosition="1" size="600,150" font="Regular;20" halign="center" valign="center" />
62         <widget name="resulttext" position="10,160" zPosition="1" size="600,110" font="Regular;20" halign="center" valign="center" />
63         <widget name="infotext2" position="10,280" zPosition="1" size="600,80" font="Regular;20" halign="center" valign="center" />
64         <widget name="kRed" position="185,365" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />       
65         <ePixmap name="red" position="185,365" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
66         <widget name="kGreen" position="330,365" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
67         <ePixmap name="green" position="330,365" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
68         </screen>"""% _("Genuine Dreambox")
69
70     def __init__(self, session):
71         Screen.__init__(self, session)
72         self["actions"] = ActionMap(["SetupActions", "ColorActions"],
73         {
74             "green": self.restart,
75             "cancel": self.exit,
76          }, -1)
77         self["kGreen"] = Button(_("Restart"))
78         self["kRed"] = Button(_("Cancel"))
79         self["infotext"] = Label("With this plugin you can verify the authenticity of your Dreambox.\nFor additional information, \nplease visit our website \nhttps://www.dream-multimedia-tv.de.")
80         self["resulttext"] = Label("... Please wait ...")
81         self["infotext2"] = Label("Please visit our website and follow the instructions.\nAlternatively you can call our customer service hotline.")
82         self.onLayoutFinish.append(self.start)
83
84     def restart(self):
85         if not self.isStart:
86             self.start()
87    
88     def start(self):
89         udsError = False
90         self.isStart = True
91         try:
92             self["resulttext"].setText("Please wait (Step 1)")
93             self.uds = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
94             self.uds.connect(("/var/run/tpmd_socket"))
95             self.uds.settimeout(5.0)
96         except:
97             self["resulttext"].setText("Security service not running.")
98             udsError = True
99         if not udsError:
100             if (self.stepFirst(TPMD_CMD_GET_DATA,[TPMD_DT_PROTOCOL_VERSION,TPMD_DT_TPM_VERSION,TPMD_DT_SERIAL])):
101                 try:  
102                     url = ("https://www.dream-multimedia-tv.de/verify/challenge?serial=%s&version=%s" % (self.serial,self.tpmdVersion))
103                     getPage(url).addCallback(self._gotPageLoadRandom).addErrback(self.errorLoad)
104                 except:
105                     self["resulttext"].setText("Can't connect to server. Please check your network!")
106
107     def _gotPageLoad(self, data):
108         authcode = data.strip().replace('+', '')
109         if len(authcode) == 12:
110             self.finish = "%s-%s-%s" % (authcode[0:4], authcode[4:8], authcode[8:12])
111             self["resulttext"].setText(self.finish)
112         else:
113             self["resulttext"].setText("Invalid response from server.")
114         self.closeUds()
115         self.isStart = False
116         
117     def _gotPageLoadRandom(self, data):
118         self["resulttext"].setText("Please wait (Step 2)")
119         self.back = data.strip()
120         self.random = (self.formatList(base64.b64decode(self.back)))
121         if (self.stepSecond(TPMD_CMD_GET_DATA,[TPMD_DT_PROTOCOL_VERSION,TPMD_DT_TPM_VERSION,TPMD_DT_SERIAL,TPMD_DT_LEVEL2_CERT,
122                 TPMD_DT_LEVEL3_CERT,TPMD_DT_FAB_CA_CERT,TPMD_DT_DATABLOCK_SIGNED] )):
123             url = self.buildUrl()
124             getPage(url).addCallback(self._gotPageLoad).addErrback(self.errorLoad) 
125
126     def errorLoad(self, error):
127         print str(error)
128         self["resulttext"].setText("Invalid response from server. Please report: %s" % str(error))
129
130     def buildUrl(self):
131         # NOTE: this is a modified base64 which uses -_ instead of +/ to avoid the need for escpaing + when using urlencode 
132         tmpra = ("random=%s" % self.back.replace('+', '-').replace('/', '_'))
133         tmpl2 = ("&l2=%s" % base64.b64encode(self.level2_cert).replace('+', '-').replace('/', '_'))
134         if self.level3_cert:
135             tmpl3 = ("&l3=%s" % base64.b64encode(self.level3_cert).replace('+', '-').replace('/', '_'))
136         else:
137             tmpl3 = ""
138         tmpfa = ("&fab=%s" % base64.b64encode(self.fab_ca_cert).replace('+', '-').replace('/', '_'))
139         tmpda = ("&data=%s" % base64.b64encode(self.datablock_signed).replace('+', '-').replace('/', '_'))
140         tmpr  = ("&r=%s" % base64.b64encode(self.r).replace('+', '-').replace('/', '_'))
141         return("https://www.dream-multimedia-tv.de/verify/challenge?%s%s%s%s%s%s&serial=%s" % (tmpra,tmpl2,tmpl3,tmpfa,tmpda,tmpr,self.serial))
142
143     def formatList(self,l):
144         liste = []
145         for x in l:
146             liste.append(ord(x))
147         return liste
148     
149     def formatString(self,s):
150         myString = ""
151         for x in s:
152             myString =  myString + chr(x)
153         return myString
154
155     def stepFirst(self,typ,daten):
156         return (self.parseResult (self.udsSend(typ,daten,len(daten)), 1))
157
158     def stepSecond(self,typ,daten):
159         if (self.parseResult(self.udsSend(typ,daten,len(daten)),2) == False):
160             return False
161         if (self.parseResult(self.udsSend(TPMD_CMD_COMPUTE_SIGNATURE,self.random,8),3) == False):
162             return False
163         return True     
164
165     def parseResult(self,rbuf,art):
166         if (rbuf != -1):
167             buf = self.formatList(rbuf)
168             if (art == 1):
169                 self.serial ="%d" % ((buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11])
170                 self.tpmdVersion = "%d" % (buf[1])
171                 self.protocolVersion = "%d" % buf[0]
172                 #print "serial:%s, version:%s, prot_version:%s" % (self.serial,self.tpmdVersion,self.protocolVersion)
173                 return True
174             elif (art == 2):
175                 tpmdata = {}
176                 while len(buf):
177                     type = buf[0]
178                     l = buf[1]
179                     data = ''.join([chr(x) for x in buf[2:l+2]])
180                     buf = buf[l+2:]
181                     tpmdata[type] = data
182                 
183                 self.level2_cert = tpmdata.get(4)
184                 self.level3_cert = tpmdata.get(5) # can be None
185                 self.fab_ca_cert = tpmdata.get(6)
186                 self.datablock_signed = tpmdata.get(7)
187                 return True            
188             elif (art == 3):
189                 self.r = self.formatString(buf)
190                 return True
191         else:
192             return False
193
194     def udsSend(self, cmdTyp, data, length):
195         udsError = False
196         sbuf = [(cmdTyp >> 8) & 0xff,(cmdTyp >> 0) & 0xff,(length >> 8) & 0xff,(length >> 0) & 0xff]
197         sbuf.extend(data[:length])
198         sbuf = struct.pack(str((length + 4))+"B", *sbuf)
199         try:
200             self.uds.send(sbuf)
201             udsError = False
202         except socket.timeout:
203             udsError = True
204         try:
205             rbuf = self.uds.recv(4)
206             udsError = False
207         except socket.timeout:
208             udsError = True
209         
210         if (udsError == False):
211             leng = [ord(rbuf[2]) << 8 | ord(rbuf[3])]
212             if (leng != 4):
213                 try:
214                     res = self.uds.recv(leng[0])
215                 except socket.timeout:
216                     udsError = True
217             else:
218                 return -1
219         else:
220             self["resulttext"].setText("Invalid response from Security service pls restart again")
221             os.system("kill -9 $(pidof tpmd)")
222             return -1
223         return res
224
225     def closeUds(self):
226        try:
227             self.uds.close()
228        except:
229             pass
230
231     def exit(self):
232         self.closeUds()
233         self.close() 
234
235 def main(session, **kwargs):
236         session.open(genuineDreambox)
237
238 def Plugins(path,**kwargs):
239         global plugin_path
240         plugin_path = path
241         return [
242                 PluginDescriptor(name="Genuine Dreambox", description="Genuine Dreambox",where = PluginDescriptor.WHERE_PLUGINMENU, icon="genuine.png", fnc=main),
243                 PluginDescriptor(name="Genuine Dreambox", where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)
244                 ]