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