commit 421901e3b0ec114336c377d58495e23ef67f7678
parent c9634a6d5735d64d59b39e534476c8e01002d6e7
Author: lash <dev@holbrook.no>
Date: Fri, 23 Jun 2023 00:20:12 +0100
Add xml schema checker
Diffstat:
8 files changed, 105 insertions(+), 30 deletions(-)
diff --git a/MANIFEST.in b/MANIFEST.in
@@ -1 +1 @@
-include *requirements* CHANGELOG WAIVER WAIVER.asc LICENSE
+include *requirements* CHANGELOG WAIVER WAIVER.asc LICENSE funga/data/*.xsd
diff --git a/funga/data/__init__.py b/funga/data/__init__.py
@@ -0,0 +1,4 @@
+# standard imports
+import os
+
+data_dir = os.path.dirname(os.path.realpath(__file__))
diff --git a/funga/data/xmldsig1-schema.xsd b/funga/data/xmldsig1-schema.xsd
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+#
+# Copyright ©[2011] World Wide Web Consortium
+# (Massachusetts Institute of Technology,
+# European Research Consortium for Informatics and Mathematics,
+# Keio University). All Rights Reserved.
+# This work is distributed under the W3C® Software License [1] 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.
+# [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+#
+-->
+
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:dsig="http://www.w3.org/TR/2004/REC-xmlschema-1-20041028/"
+ targetNamespace="http://www.w3.org/2000/09/xmldsig#"
+ version="0.1" elementFormDefault="qualified">
+
+ <include
+ schemaLocation="http://www.w3.org/TR/2008/REC-xmldsig-core-20080610/xmldsig-core-schema.xsd"/>
+
+
+ <import namespace="http://www.w3.org/2009/xmldsig11#"
+ schemaLocation="http://www.w3.org/TR/xmldsig-core/xmldsig11-schema.xsd"/>
+</schema>
+
diff --git a/funga/xml/xml.py b/funga/xml/xml.py
@@ -1,15 +1,20 @@
# standard imports
+import os
from enum import Enum
import logging
import xml.etree.ElementTree as ET
from base64 import b64decode
+# local imports
+from funga.data import data_dir
+
logg = logging.getLogger(__name__)
SignatureAccept = Enum('SignatureAccept', 'CANONICALIZATION SIGNING TRANSFORM DIGEST')
SignatureVerify = Enum('SignatureVerify', 'SIGNATURE DIGEST PUBLICKEY')
+
def cryptobinary_to_int(v):
b = b64decode(v)
return int.from_bytes(b, byteorder='big')
@@ -22,7 +27,7 @@ class SignatureParser:
'dsig11': "http://www.w3.org/2009/xmldsig11",
}
- def __init__(self):
+ def __init__(self, validate_schema=True):
self.__tree = None
self.__signature_verifier = None
self.__settings = [
@@ -36,22 +41,34 @@ class SignatureParser:
None,
None,
]
- self.__r = None
+ self.__schema = None
+ if validate_schema:
+ self.__load_schema_validator()
self.clear()
+
+ def __load_schema_validator(self):
+ import importlib
+ m = None
+ try:
+ m = importlib.import_module('xmlschema')
+ except ModuleNotFoundError:
+ return
+ sp = os.path.join(data_dir, 'xmldsig1-schema.xsd')
+ self.__schema = m.XMLSchema(sp)
+
def clear(self):
- self.__r = {
- 'sig': None,
- 'pubkey': None,
- 'prime': None,
- 'curve_a': None,
- 'curve_b': None,
- 'base': None,
- 'order': None,
- 'cofactor': None,
- 'keyname': None,
- }
+ self.signature = None
+ self.digest = None
+ self.public_key = None
+ self.prime = None
+ self.curve_a = None
+ self.curve_b = None
+ self.base = None
+ self.order = None
+ self.cofactor = None
+ self.keyname = None
def set(self, k, v):
@@ -69,8 +86,15 @@ class SignatureParser:
return self.__verify[k.value - 1]
raise ValueError('invalid key: {}'.format(k))
+
+ def __verify_schema(self, fp):
+ if self.__schema == None:
+ return
+ schema.validate(fp)
+
def process_file(self, fp):
+ self.__verify_schema(fp)
self.__tree = ET.parse(fp)
self.__root = self.__tree.getroot()
self.__verify_canonicalization(self.__root[0][0])
@@ -82,7 +106,6 @@ class SignatureParser:
r = self.__root.find('./KeyInfo', namespaces=self.namespaces)
if r != None:
self.__opt_verify_keyinfo(r)
- logg.debug('result {}'.format(self.__r))
def __verify_canonicalization(self, el):
@@ -98,7 +121,7 @@ class SignatureParser:
m = self.get(SignatureVerify.SIGNATURE)
if m != None:
assert m(b)
- self.__r['sig'] = b
+ self.signature = b
def __opt_verify_signedinfo(self, el):
r = el.find('./DigestMethod', namespaces=self.namespaces)
@@ -110,17 +133,17 @@ class SignatureParser:
m = self.get(SignatureVerify.DIGEST)
if m != None:
assert m(b)
- self.__r['digest'] = b
+ self.digest = b
def __opt_verify_keyinfo(self, el):
r = el.find('./dsig11:ECKeyValue', namespaces=self.namespaces)
if r != None:
- assert self.__opt_verify_keyinfo_eckey(r)
+ self.__opt_verify_keyinfo_eckey(r)
r = el.find('./KeyName', namespaces=self.namespaces)
if r != None:
- self.__r['keyname'] = r.text
+ self.keyname = r.text
def __opt_verify_keyinfo_eckey(self, el):
@@ -130,18 +153,17 @@ class SignatureParser:
m = self.get(SignatureVerify.PUBLICKEY)
if m != None:
assert m(b)
- self.__r['pubkey'] = b
+ self.public_key = b
r = el.find('./dsig11:ECParameters/dsig11:FieldID/dsig11:Prime/dsig11:P', namespaces=self.namespaces)
- self.__r['prime'] = cryptobinary_to_int(r.text)
+ self.prime = cryptobinary_to_int(r.text)
r = el.find('./dsig11:ECParameters/dsig11:Curve/dsig11:A', namespaces=self.namespaces)
- self.__r['curve_a'] = cryptobinary_to_int(r.text)
+ self.curve_a = cryptobinary_to_int(r.text)
r = el.find('./dsig11:ECParameters/dsig11:Curve/dsig11:B', namespaces=self.namespaces)
- self.__r['curve_b'] = cryptobinary_to_int(r.text)
+ self.curve_b = cryptobinary_to_int(r.text)
r = el.find('./dsig11:ECParameters/dsig11:Base', namespaces=self.namespaces)
- self.__r['base'] = cryptobinary_to_int(r.text)
+ self.base = cryptobinary_to_int(r.text)
r = el.find('./dsig11:ECParameters/dsig11:Order', namespaces=self.namespaces)
- self.__r['order'] = cryptobinary_to_int(r.text)
+ self.order = cryptobinary_to_int(r.text)
r = el.find('./dsig11:ECParameters/dsig11:CoFactor', namespaces=self.namespaces)
- self.__r['cofactor'] = int(r.text)
-
- return True
+ if r != None:
+ self.cofactor = int(r.text)
diff --git a/setup.py b/setup.py
@@ -22,9 +22,18 @@ while True:
test_requirements.append(l.rstrip())
f.close()
+xml_requirements = []
+f = open('xml_requirements.txt', 'r')
+while True:
+ l = f.readline()
+ if l == '':
+ break
+ xml_requirements.append(l.rstrip())
+f.close()
+
setup(
name="funga",
- version="0.5.6",
+ version="0.5.7",
description="A signer and keystore daemon and library for cryptocurrency software development",
author="Louis Holbrook",
author_email="dev@holbrook.no",
@@ -35,5 +44,8 @@ setup(
tests_require=test_requirements,
long_description=long_description,
long_description_content_type='text/markdown',
+ extras_require={
+ 'xml': xml_requirements,
+ },
url='https://git.defalsify.org/funga',
)
diff --git a/tests/test_xml.py b/tests/test_xml.py
@@ -39,13 +39,16 @@ class TestXmlSig(unittest.TestCase):
with self.assertRaises(AssertionError):
self.parser.process_file(self.xml_file)
self.parser.set(SignatureAccept.CANONICALIZATION, 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
+
with self.assertRaises(AssertionError):
self.parser.process_file(self.xml_file)
self.parser.set(SignatureAccept.SIGNING, 'http://tools.ietf.org/html/rfc6931')
+
with self.assertRaises(AssertionError):
self.parser.process_file(self.xml_file)
self.parser.set(SignatureAccept.DIGEST, 'https://csrc.nist.gov/glossary/term/sha_256')
self.parser.process_file(self.xml_file)
+
self.parser.set(SignatureVerify.SIGNATURE, verify_fail)
with self.assertRaises(AssertionError):
self.parser.process_file(self.xml_file)
@@ -70,6 +73,10 @@ class TestXmlSig(unittest.TestCase):
self.parser.set(SignatureVerify.PUBLICKEY, verify_pub_ok)
self.parser.process_file(self.xml_file)
+ self.assertEqual(self.parser.signature.hex(), 'af77767edbccdf46380fed6f06af43c807de4bedce2eda129923340e9577c97e76bc55d587103a367057167f351ae1cfd6b8dea6e0282257de3594fbe3d8780700')
+ self.assertEqual(self.parser.public_key.hex(), '049f6bb6a7e3f5b7ee71756a891233d1415658f8712bac740282e083dc9240f5368bdb3b256a5bf40a8f7f9753414cb447ee3f796c5f30f7eb40a7f5018fc7f02e')
+ self.assertEqual(self.parser.digest.hex(), '76b2e96714d3b5e6eb1d1c509265430b907b44f72b2a22b06fcd4d96372b8565')
+
if __name__ == '__main__':
unittest.main()
diff --git a/tests/testdata/sign.xml b/tests/testdata/sign.xml
@@ -15,7 +15,7 @@
<SignatureValue>r3d2ftvM30Y4D+1vBq9DyAfeS+3OLtoSmSM0DpV3yX52vFXVhxA6NnBXFn81GuHP1rjepuAoIlfeNZT749h4BwA=</SignatureValue>
<KeyInfo>
- <KeyName>eb3907ecad74a0013c259d5874ae7f22dcbcc95c</KeyName>
+ <KeyName>6zkH7K10oAE8JZ1YdK5/Ity8yVw=</KeyName>
<!-- public key: 049f6bb6a7e3f5b7ee71756a891233d1415658f8712bac740282e083dc9240f5368bdb3b256a5bf40a8f7f9753414cb447ee3f796c5f30f7eb40a7f5018fc7f02e -->
<ECKeyValue xmlns="http://www.w3.org/2009/xmldsig11">
<PublicKey>BJ9rtqfj9bfucXVqiRIz0UFWWPhxK6x0AoLgg9ySQPU2i9s7JWpb9AqPf5dTQUy0R+4/eWxfMPfrQKf1AY/H8C4=</PublicKey>
diff --git a/xml_requirements.txt b/xml_requirements.txt
@@ -0,0 +1 @@
+xmlschema~=2.3.1