11ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import 230e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import * 391bca4244286fb519c93fe92329da96b0e6f32eejvrfrom fontTools.misc.textTools import safeEval 48413c108d21e8cf0e9059bbfffde8d13f2616340Behdad Esfahbodfrom fontTools.misc import sstruct 530e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom . import DefaultTable 6816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbodimport base64 791bca4244286fb519c93fe92329da96b0e6f32eejvr 891bca4244286fb519c93fe92329da96b0e6f32eejvrDSIG_HeaderFormat = """ 991bca4244286fb519c93fe92329da96b0e6f32eejvr > # big endian 1091bca4244286fb519c93fe92329da96b0e6f32eejvr ulVersion: L 1191bca4244286fb519c93fe92329da96b0e6f32eejvr usNumSigs: H 1291bca4244286fb519c93fe92329da96b0e6f32eejvr usFlag: H 1391bca4244286fb519c93fe92329da96b0e6f32eejvr""" 1491bca4244286fb519c93fe92329da96b0e6f32eejvr# followed by an array of usNumSigs DSIG_Signature records 1591bca4244286fb519c93fe92329da96b0e6f32eejvrDSIG_SignatureFormat = """ 1691bca4244286fb519c93fe92329da96b0e6f32eejvr > # big endian 1791bca4244286fb519c93fe92329da96b0e6f32eejvr ulFormat: L 1891bca4244286fb519c93fe92329da96b0e6f32eejvr ulLength: L # length includes DSIG_SignatureBlock header 1991bca4244286fb519c93fe92329da96b0e6f32eejvr ulOffset: L 2091bca4244286fb519c93fe92329da96b0e6f32eejvr""" 2191bca4244286fb519c93fe92329da96b0e6f32eejvr# followed by an array of usNumSigs DSIG_SignatureBlock records, 2291bca4244286fb519c93fe92329da96b0e6f32eejvr# each followed immediately by the pkcs7 bytes 2391bca4244286fb519c93fe92329da96b0e6f32eejvrDSIG_SignatureBlockFormat = """ 2491bca4244286fb519c93fe92329da96b0e6f32eejvr > # big endian 2591bca4244286fb519c93fe92329da96b0e6f32eejvr usReserved1: H 2691bca4244286fb519c93fe92329da96b0e6f32eejvr usReserved2: H 2791bca4244286fb519c93fe92329da96b0e6f32eejvr cbSignature: l # length of following raw pkcs7 data 2891bca4244286fb519c93fe92329da96b0e6f32eejvr""" 2991bca4244286fb519c93fe92329da96b0e6f32eejvr 3091bca4244286fb519c93fe92329da96b0e6f32eejvr# 3191bca4244286fb519c93fe92329da96b0e6f32eejvr# NOTE 3291bca4244286fb519c93fe92329da96b0e6f32eejvr# the DSIG table format allows for SignatureBlocks residing 3391bca4244286fb519c93fe92329da96b0e6f32eejvr# anywhere in the table and possibly in a different order as 3491bca4244286fb519c93fe92329da96b0e6f32eejvr# listed in the array after the first table header 3591bca4244286fb519c93fe92329da96b0e6f32eejvr# 3691bca4244286fb519c93fe92329da96b0e6f32eejvr# this implementation does not keep track of any gaps and/or data 3791bca4244286fb519c93fe92329da96b0e6f32eejvr# before or after the actual signature blocks while decompiling, 3891bca4244286fb519c93fe92329da96b0e6f32eejvr# and puts them in the same physical order as listed in the header 3991bca4244286fb519c93fe92329da96b0e6f32eejvr# on compilation with no padding whatsoever. 4091bca4244286fb519c93fe92329da96b0e6f32eejvr# 417842e56b97ce677b83bdab09cda48bc2d89ac75aJust 427842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass table_D_S_I_G_(DefaultTable.DefaultTable): 437842e56b97ce677b83bdab09cda48bc2d89ac75aJust 4491bca4244286fb519c93fe92329da96b0e6f32eejvr def decompile(self, data, ttFont): 4591bca4244286fb519c93fe92329da96b0e6f32eejvr dummy, newData = sstruct.unpack2(DSIG_HeaderFormat, data, self) 4691bca4244286fb519c93fe92329da96b0e6f32eejvr assert self.ulVersion == 1, "DSIG ulVersion must be 1" 4791bca4244286fb519c93fe92329da96b0e6f32eejvr assert self.usFlag & ~1 == 0, "DSIG usFlag must be 0x1 or 0x0" 4891bca4244286fb519c93fe92329da96b0e6f32eejvr self.signatureRecords = sigrecs = [] 4991bca4244286fb519c93fe92329da96b0e6f32eejvr for n in range(self.usNumSigs): 5091bca4244286fb519c93fe92329da96b0e6f32eejvr sigrec, newData = sstruct.unpack2(DSIG_SignatureFormat, newData, SignatureRecord()) 5191bca4244286fb519c93fe92329da96b0e6f32eejvr assert sigrec.ulFormat == 1, "DSIG signature record #%d ulFormat must be 1" % n 5291bca4244286fb519c93fe92329da96b0e6f32eejvr sigrecs.append(sigrec) 5391bca4244286fb519c93fe92329da96b0e6f32eejvr for sigrec in sigrecs: 5491bca4244286fb519c93fe92329da96b0e6f32eejvr dummy, newData = sstruct.unpack2(DSIG_SignatureBlockFormat, data[sigrec.ulOffset:], sigrec) 5591bca4244286fb519c93fe92329da96b0e6f32eejvr assert sigrec.usReserved1 == 0, "DSIG signature record #%d usReserverd1 must be 0" % n 5691bca4244286fb519c93fe92329da96b0e6f32eejvr assert sigrec.usReserved2 == 0, "DSIG signature record #%d usReserverd2 must be 0" % n 5791bca4244286fb519c93fe92329da96b0e6f32eejvr sigrec.pkcs7 = newData[:sigrec.cbSignature] 5891bca4244286fb519c93fe92329da96b0e6f32eejvr 5991bca4244286fb519c93fe92329da96b0e6f32eejvr def compile(self, ttFont): 6091bca4244286fb519c93fe92329da96b0e6f32eejvr packed = sstruct.pack(DSIG_HeaderFormat, self) 6191bca4244286fb519c93fe92329da96b0e6f32eejvr headers = [packed] 6291bca4244286fb519c93fe92329da96b0e6f32eejvr offset = len(packed) + self.usNumSigs * sstruct.calcsize(DSIG_SignatureFormat) 6391bca4244286fb519c93fe92329da96b0e6f32eejvr data = [] 6491bca4244286fb519c93fe92329da96b0e6f32eejvr for sigrec in self.signatureRecords: 6591bca4244286fb519c93fe92329da96b0e6f32eejvr # first pack signature block 6691bca4244286fb519c93fe92329da96b0e6f32eejvr sigrec.cbSignature = len(sigrec.pkcs7) 6791bca4244286fb519c93fe92329da96b0e6f32eejvr packed = sstruct.pack(DSIG_SignatureBlockFormat, sigrec) + sigrec.pkcs7 6891bca4244286fb519c93fe92329da96b0e6f32eejvr data.append(packed) 6991bca4244286fb519c93fe92329da96b0e6f32eejvr # update redundant length field 7091bca4244286fb519c93fe92329da96b0e6f32eejvr sigrec.ulLength = len(packed) 7191bca4244286fb519c93fe92329da96b0e6f32eejvr # update running table offset 7291bca4244286fb519c93fe92329da96b0e6f32eejvr sigrec.ulOffset = offset 7391bca4244286fb519c93fe92329da96b0e6f32eejvr headers.append(sstruct.pack(DSIG_SignatureFormat, sigrec)) 7491bca4244286fb519c93fe92329da96b0e6f32eejvr offset += sigrec.ulLength 751a3909756d1b3bb71530df821d239977a64a18e8Behdad Esfahbod if offset % 2: 761a3909756d1b3bb71530df821d239977a64a18e8Behdad Esfahbod # Pad to even bytes 771a3909756d1b3bb71530df821d239977a64a18e8Behdad Esfahbod data.append(b'\0') 7818316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod return bytesjoin(headers+data) 7991bca4244286fb519c93fe92329da96b0e6f32eejvr 807842e56b97ce677b83bdab09cda48bc2d89ac75aJust def toXML(self, xmlWriter, ttFont): 817842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.comment("note that the Digital Signature will be invalid after recompilation!") 827842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.newline() 8391bca4244286fb519c93fe92329da96b0e6f32eejvr xmlWriter.simpletag("tableHeader", version=self.ulVersion, numSigs=self.usNumSigs, flag="0x%X" % self.usFlag) 8491bca4244286fb519c93fe92329da96b0e6f32eejvr for sigrec in self.signatureRecords: 8591bca4244286fb519c93fe92329da96b0e6f32eejvr xmlWriter.newline() 8691bca4244286fb519c93fe92329da96b0e6f32eejvr sigrec.toXML(xmlWriter, ttFont) 877842e56b97ce677b83bdab09cda48bc2d89ac75aJust xmlWriter.newline() 8891bca4244286fb519c93fe92329da96b0e6f32eejvr 893a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content, ttFont): 9091bca4244286fb519c93fe92329da96b0e6f32eejvr if name == "tableHeader": 9191bca4244286fb519c93fe92329da96b0e6f32eejvr self.signatureRecords = [] 9291bca4244286fb519c93fe92329da96b0e6f32eejvr self.ulVersion = safeEval(attrs["version"]) 9391bca4244286fb519c93fe92329da96b0e6f32eejvr self.usNumSigs = safeEval(attrs["numSigs"]) 9491bca4244286fb519c93fe92329da96b0e6f32eejvr self.usFlag = safeEval(attrs["flag"]) 9591bca4244286fb519c93fe92329da96b0e6f32eejvr return 9691bca4244286fb519c93fe92329da96b0e6f32eejvr if name == "SignatureRecord": 9791bca4244286fb519c93fe92329da96b0e6f32eejvr sigrec = SignatureRecord() 983a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod sigrec.fromXML(name, attrs, content, ttFont) 9991bca4244286fb519c93fe92329da96b0e6f32eejvr self.signatureRecords.append(sigrec) 10091bca4244286fb519c93fe92329da96b0e6f32eejvr 10191bca4244286fb519c93fe92329da96b0e6f32eejvrpem_spam = lambda l, spam = { 10291bca4244286fb519c93fe92329da96b0e6f32eejvr "-----BEGIN PKCS7-----": True, "-----END PKCS7-----": True, "": True 10391bca4244286fb519c93fe92329da96b0e6f32eejvr}: not spam.get(l.strip()) 10491bca4244286fb519c93fe92329da96b0e6f32eejvr 105816df48e03957e937ff389acdbccd4889d840491Behdad Esfahboddef b64encode(b): 106816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod s = base64.b64encode(b) 107816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod # Line-break at 76 chars. 108816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod items = [] 109816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod while s: 110816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod items.append(tostr(s[:76])) 111816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod items.append('\n') 112816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod s = s[76:] 113816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod return strjoin(items) 114816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod 115e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass SignatureRecord(object): 11691bca4244286fb519c93fe92329da96b0e6f32eejvr def __repr__(self): 11791bca4244286fb519c93fe92329da96b0e6f32eejvr return "<%s: %s>" % (self.__class__.__name__, self.__dict__) 11891bca4244286fb519c93fe92329da96b0e6f32eejvr 11991bca4244286fb519c93fe92329da96b0e6f32eejvr def toXML(self, writer, ttFont): 12091bca4244286fb519c93fe92329da96b0e6f32eejvr writer.begintag(self.__class__.__name__, format=self.ulFormat) 12191bca4244286fb519c93fe92329da96b0e6f32eejvr writer.newline() 12291bca4244286fb519c93fe92329da96b0e6f32eejvr writer.write_noindent("-----BEGIN PKCS7-----\n") 123816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod writer.write_noindent(b64encode(self.pkcs7)) 12491bca4244286fb519c93fe92329da96b0e6f32eejvr writer.write_noindent("-----END PKCS7-----\n") 12591bca4244286fb519c93fe92329da96b0e6f32eejvr writer.endtag(self.__class__.__name__) 12691bca4244286fb519c93fe92329da96b0e6f32eejvr 1273a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod def fromXML(self, name, attrs, content, ttFont): 12891bca4244286fb519c93fe92329da96b0e6f32eejvr self.ulFormat = safeEval(attrs["format"]) 12991bca4244286fb519c93fe92329da96b0e6f32eejvr self.usReserved1 = safeEval(attrs.get("reserved1", "0")) 13091bca4244286fb519c93fe92329da96b0e6f32eejvr self.usReserved2 = safeEval(attrs.get("reserved2", "0")) 131816df48e03957e937ff389acdbccd4889d840491Behdad Esfahbod self.pkcs7 = base64.b64decode(tobytes(strjoin(filter(pem_spam, content)))) 132