93 lines
3.4 KiB
Python
Executable File
93 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright (C) 2006 Søren Roug, European Environment Agency
|
|
#
|
|
# This is free software. You may redistribute it under the terms
|
|
# of the Apache license and the GNU General Public License Version
|
|
# 2 or at your option any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public
|
|
# License along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
#
|
|
# Contributor(s):
|
|
#
|
|
# Requires PyXML
|
|
import sha,base64,zipfile,sys
|
|
from xml.dom.ext.reader import PyExpat
|
|
from xml.dom.ext.c14n import Canonicalize
|
|
import StringIO
|
|
|
|
|
|
def data_digest(data):
|
|
return base64.b64encode(sha.new(data).digest())
|
|
|
|
def xml_digest(dom):
|
|
s = StringIO.StringIO()
|
|
Canonicalize(dom,s)
|
|
canon = s.getvalue().encode('utf-8')
|
|
return data_digest(canon)
|
|
|
|
def get_signatureproperty(dom, ref):
|
|
property_list = dom.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','SignatureProperty')
|
|
for p in property_list:
|
|
id = p.getAttributeNS(None,'Id')
|
|
if ref == id: return p
|
|
return None
|
|
|
|
def exitwithusage(exitcode=2):
|
|
sys.stderr.write("Usage: %s inputfile\n" % sys.argv[0])
|
|
sys.exit(exitcode)
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) != 2:
|
|
exitwithusage()
|
|
z = zipfile.ZipFile(sys.argv[1])
|
|
namelist = z.namelist()
|
|
if "META-INF/documentsignatures.xml" not in namelist:
|
|
print "This document is not signed"
|
|
sys.exit()
|
|
documentsignatures_xml = z.read('META-INF/documentsignatures.xml')
|
|
reader = PyExpat.Reader()
|
|
doc = reader.fromString(documentsignatures_xml)
|
|
|
|
signature_list = doc.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','Signature')
|
|
print "Document has %s signature(s)" % len(signature_list)
|
|
signnum = 1
|
|
for signature in signature_list:
|
|
date = signature.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/","date")[0].firstChild.nodeValue
|
|
# print date.__dict__
|
|
|
|
print "Checking signature #%d - signed on %s" % (signnum, date),
|
|
refs = signature.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','Reference')
|
|
for ref in refs:
|
|
status = "OK"
|
|
uri = ref.getAttributeNS(None,'URI')
|
|
digest_value = ref.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','DigestValue')[0].firstChild.nodeValue
|
|
if uri[0] != '#':
|
|
document = z.read(uri)
|
|
if uri[-4:] == ".xml" and len(document) != 0:
|
|
dom = PyExpat.Reader().fromString(document)
|
|
digest_actual = xml_digest(dom)
|
|
else:
|
|
digest_actual = data_digest(document)
|
|
else:
|
|
# FIXME
|
|
# fragments aren't canonicalized. See http://www.w3.org/TR/xmldsig-core/#sec-URI
|
|
xmlfragment = get_signatureproperty(doc, uri[1:])
|
|
if xmlfragment is None:
|
|
continue
|
|
digest_actual = digest_value
|
|
#digest_actual = xml_digest(xmlfragment)
|
|
if digest_value != digest_actual:
|
|
status = "failed"
|
|
|
|
print status
|
|
signnum += 1
|
|
|