1 # -*- coding: utf-8 -*-
2 ###########################################################################
8 # Copyright (C) 2009 by
9 # <nixkoenner@newnigma2.to>
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.
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.
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.
27 ###########################################################################
29 # thx to <kayshadow@newnigma2.to> for painting the icon
31 from Plugins.Plugin import PluginDescriptor
32 from Screens.Screen import Screen
33 from Screens.MessageBox import MessageBox
35 from Components.ActionMap import ActionMap
36 from Components.Button import Button
37 from Components.Label import Label
44 from twisted.web.client import getPage
46 TPMD_DT_RESERVED = 0x00
47 TPMD_DT_PROTOCOL_VERSION = 0x01
48 TPMD_DT_TPM_VERSION = 0x02
50 TPMD_DT_LEVEL2_CERT = 0x04
51 TPMD_DT_LEVEL3_CERT = 0x05
52 TPMD_DT_FAB_CA_CERT = 0x06
53 TPMD_DT_DATABLOCK_SIGNED = 0x07
54 TPMD_CMD_RESERVED = 0x0000
55 TPMD_CMD_GET_DATA = 0x0001
56 TPMD_CMD_APDU = 0x0002
57 TPMD_CMD_COMPUTE_SIGNATURE = 0x0003
58 TPMD_CMD_APP_CERT = 0x0004
61 class genuineDreambox(Screen):
63 <screen position="center,center" size="620,420" title="%s" >
64 <widget name="infotext" position="10,20" zPosition="1" size="600,150" font="Regular;20" halign="center" valign="center" />
65 <widget name="resulttext" position="10,160" zPosition="1" size="600,110" font="Regular;20" halign="center" valign="center" />
66 <widget name="infotext2" position="10,280" zPosition="1" size="600,80" font="Regular;20" halign="center" valign="center" />
67 <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" />
68 <ePixmap name="red" position="185,365" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
69 <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" />
70 <ePixmap name="green" position="330,365" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
71 </screen>"""% _("Genuine Dreambox")
73 def __init__(self, session):
74 Screen.__init__(self, session)
75 self["actions"] = ActionMap(["SetupActions", "ColorActions"],
77 "green": self.restart,
80 self["kGreen"] = Button(_("Test again"))
81 self["kRed"] = Button(_("Cancel"))
82 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.")
83 self["resulttext"] = Label("... Please wait ...")
84 self["infotext2"] = Label("Please visit our website and follow the instructions.\nAlternatively you can call our customer service hotline.")
85 self.onLayoutFinish.append(self.start)
95 self["resulttext"].setText("Please wait (Step 1)")
96 self.uds = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
97 self.uds.connect(("/var/run/tpmd_socket"))
98 self.uds.settimeout(5.0)
100 self["resulttext"].setText("Security service not running.")
103 if (self.stepFirst(TPMD_CMD_GET_DATA,[TPMD_DT_PROTOCOL_VERSION,TPMD_DT_TPM_VERSION,TPMD_DT_SERIAL])):
105 url = ("https://www.dream-multimedia-tv.de/verify/challenge?serial=%s&version=%s" % (self.serial,self.tpmdVersion))
106 getPage(url).addCallback(self._gotPageLoadRandom).addErrback(self.errorLoad)
108 self["resulttext"].setText(_("Can't connect to server. Please check your network!"))
110 def needsTPMUpdate(self):
111 return self.level3_cert is None
113 def updateCallback(self, result):
116 url = self.buildUrlUpdate()
117 #url = ("https://www.dream-multimedia-tv.de/verify/challenge?serial=%s&version=%s" % (self.serial,self.tpmdVersion))
118 self["resulttext"].setText(_("Updating, please wait..."))
119 getPage(url).addCallback(self._gotPageLoadUpdate).addErrback(self.errorLoad)
123 def _gotPageLoad(self, data):
124 authcode = data.strip().replace('+', '')
125 if len(authcode) == 12:
126 self.finish = "%s-%s-%s" % (authcode[0:4], authcode[4:8], authcode[8:12])
127 self["resulttext"].setText(self.finish)
128 if self.needsTPMUpdate():
129 if int(self.protocolVersion) >= TPMD_PV_2:
130 self.session.openWithCallback(self.updateCallback, MessageBox, _("There's a certificate update available for your dreambox. Would you like to apply this update now?"))
132 self["resulttext"].setText(_("Invalid response from server."))
136 def _gotPageLoadRandom(self, data):
137 self["resulttext"].setText(_("Please wait (Step 2)"))
138 self.back = data.strip()
139 self.random = (self.formatList(base64.b64decode(self.back)))
140 self.level2_cert = None
141 self.level3_cert = None
142 if (self.stepSecond(TPMD_CMD_GET_DATA,[TPMD_DT_PROTOCOL_VERSION,TPMD_DT_TPM_VERSION,TPMD_DT_SERIAL,TPMD_DT_LEVEL2_CERT,
143 TPMD_DT_LEVEL3_CERT,TPMD_DT_FAB_CA_CERT,TPMD_DT_DATABLOCK_SIGNED] )):
144 url = self.buildUrl()
145 getPage(url).addCallback(self._gotPageLoad).addErrback(self.errorLoad)
147 def _gotPageLoadUpdate(self, data):
148 updatedata = base64.decodestring(data)
149 if len(updatedata) != 409:
150 self["resulttext"].setText(_("Updating failed. Nothing is broken, just the update couldn't be applied."))
156 self.uds = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
157 self.uds.connect(("/var/run/tpmd_socket"))
158 self.uds.settimeout(5.0)
160 self["resulttext"].setText(_("Security service not running."))
164 data.extend(updatedata)
165 data = self.formatList(data)
166 self.udsSend(TPMD_CMD_APP_CERT, data, 410)
167 self["resulttext"].setText(_("Update done..."))
170 self.session.openWithCallback(self.updateFinished, MessageBox, _("Update done... The genuine dreambox test will now be rerun and should not ask you to update again."), MessageBox.TYPE_INFO)
172 def updateFinished(self, result):
175 def errorLoad(self, error):
177 self["resulttext"].setText(_("Invalid response from server. Please report: %s") % str(error))
180 # NOTE: this is a modified base64 which uses -_ instead of +/ to avoid the need for escpaing + when using urlencode
181 tmpra = ("random=%s" % self.back.replace('+', '-').replace('/', '_'))
182 tmpl2 = ("&l2=%s" % base64.b64encode(self.level2_cert).replace('+', '-').replace('/', '_'))
183 if self.level3_cert is not None:
184 tmpl3 = ("&l3=%s" % base64.b64encode(self.level3_cert).replace('+', '-').replace('/', '_'))
187 tmpfa = ("&fab=%s" % base64.b64encode(self.fab_ca_cert).replace('+', '-').replace('/', '_'))
188 tmpda = ("&data=%s" % base64.b64encode(self.datablock_signed).replace('+', '-').replace('/', '_'))
189 tmpr = ("&r=%s" % base64.b64encode(self.r).replace('+', '-').replace('/', '_'))
190 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))
192 def buildUrlUpdate(self):
193 return self.buildUrl() + "&getupdate=true"
195 def formatList(self,l):
201 def formatString(self,s):
204 myString = myString + chr(x)
207 def stepFirst(self,typ,daten):
208 return (self.parseResult (self.udsSend(typ,daten,len(daten))))
210 def stepSecond(self,typ,daten):
211 if (self.parseResult(self.udsSend(typ,daten,len(daten))) == False):
213 if (self.parseSignature(self.udsSend(TPMD_CMD_COMPUTE_SIGNATURE,self.random,8)) == False):
217 def parseResult(self,rbuf):
219 buf = self.formatList(rbuf)
222 while pos < len(buf):
224 length = buf[pos + 1]
225 value = buf[pos + 2: pos + 2 + length]
226 if tag == TPMD_DT_PROTOCOL_VERSION:
228 self.protocolVersion = None
230 self.protocolVersion = "%d" % value[0]
231 elif tag == TPMD_DT_TPM_VERSION:
233 self.tpmdVersion = None
235 self.tpmdVersion = "%d" % value[0]
236 elif tag == TPMD_DT_SERIAL:
240 self.serial = "%d" % ((value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3])
241 elif tag == TPMD_DT_LEVEL2_CERT:
243 self.level2_cert = None
245 self.level2_cert = ''.join([chr(x) for x in value])
246 elif tag == TPMD_DT_LEVEL3_CERT:
248 self.level3_cert = None
250 self.level3_cert = ''.join([chr(x) for x in value])
251 elif tag == TPMD_DT_FAB_CA_CERT:
253 self.fab_ca_cert = None
255 self.fab_ca_cert = ''.join([chr(x) for x in value])
256 elif tag == TPMD_DT_DATABLOCK_SIGNED:
258 self.datablock_signed = None
260 self.datablock_signed = ''.join([chr(x) for x in value])
262 print "unknown tag:", tag
269 def parseSignature(self, rbuf):
271 self.r = self.formatString(self.formatList(rbuf))
276 def udsSend(self, cmdTyp, data, length):
278 sbuf = [(cmdTyp >> 8) & 0xff,(cmdTyp >> 0) & 0xff,(length >> 8) & 0xff,(length >> 0) & 0xff]
279 sbuf.extend(data[:length])
280 sbuf = struct.pack(str((length + 4))+"B", *sbuf)
284 except socket.timeout:
287 rbuf = self.uds.recv(4)
289 except socket.timeout:
294 if (udsError == False):
295 leng = [ord(rbuf[2]) << 8 | ord(rbuf[3])]
298 res = self.uds.recv(leng[0])
299 except socket.timeout:
304 self["resulttext"].setText(_("Invalid response from Security service pls restart again"))
305 os.system("kill -9 $(pidof tpmd)")
319 def main(session, **kwargs):
320 session.open(genuineDreambox)
322 def Plugins(path,**kwargs):
326 PluginDescriptor(name="Genuine Dreambox", description="Genuine Dreambox",where = PluginDescriptor.WHERE_PLUGINMENU, icon="genuine.png", fnc=main),
327 PluginDescriptor(name="Genuine Dreambox", where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)