Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2017-09-22 11:53:19 +0200
committerArthur de Jong <arthur@arthurdejong.org>2017-12-27 19:04:26 +0100
commitea503d6590e3a3ede8e119da3887d8543731cf9a (patch)
tree8d081cf6dbe5fd33a3d821b94cc0343aad96262d
parentfcc6cdb0320cdae1206f2f231c2f5bca56b9b847 (diff)
Implement basic parsing of signature properties
-rw-r--r--pskc/__init__.py2
-rw-r--r--pskc/parser.py30
-rw-r--r--pskc/signature.py68
-rw-r--r--tests/test_draft_ietf_keyprov_pskc_02.doctest12
-rw-r--r--tests/test_rfc6030.doctest14
5 files changed, 125 insertions, 1 deletions
diff --git a/pskc/__init__.py b/pskc/__init__.py
index 3ceaba2..920e906 100644
--- a/pskc/__init__.py
+++ b/pskc/__init__.py
@@ -72,10 +72,12 @@ class PSKC(object):
def __init__(self, filename=None):
from pskc.encryption import Encryption
+ from pskc.signature import Signature
from pskc.mac import MAC
self.version = None
self.id = None
self.encryption = Encryption(self)
+ self.signature = Signature(self)
self.mac = MAC(self)
self.devices = []
if filename is not None:
diff --git a/pskc/parser.py b/pskc/parser.py
index abad663..fac302a 100644
--- a/pskc/parser.py
+++ b/pskc/parser.py
@@ -90,6 +90,8 @@ class PSKCParser(object):
# handle KeyPackage entries
for key_package in findall(container, 'KeyPackage', 'Device'):
cls.parse_key_package(pskc.add_device(), key_package)
+ # handle Signature entries
+ cls.parse_signature(pskc.signature, find(container, 'Signature'))
@classmethod
def parse_encryption(cls, encryption, key_info):
@@ -360,3 +362,31 @@ class PSKCParser(object):
for child in policy_elm:
if child.tag not in known_children:
policy.unknown_policy_elements = True
+
+ @classmethod
+ def parse_signature(cls, signature, signature_elm):
+ """Read signature information from the <Signature> element."""
+ if signature_elm is None:
+ return
+ cm_elm = find(signature_elm, 'SignedInfo/CanonicalizationMethod')
+ if cm_elm is not None:
+ signature.canonicalization_method = cm_elm.attrib.get('Algorithm')
+ sm_elm = find(signature_elm, 'SignedInfo/SignatureMethod')
+ if sm_elm is not None:
+ signature.algorithm = sm_elm.attrib.get('Algorithm')
+ dm_elm = find(signature_elm, 'SignedInfo/Reference/DigestMethod')
+ if dm_elm is not None:
+ signature.digest_algorithm = dm_elm.attrib.get('Algorithm')
+ issuer = find(signature_elm, 'KeyInfo/X509Data/X509IssuerSerial')
+ if issuer is not None:
+ signature.issuer = findtext(issuer, 'X509IssuerName')
+ signature.serial = findtext(issuer, 'X509SerialNumber')
+ certificate = findbin(
+ signature_elm, 'KeyInfo/X509Data/X509Certificate')
+ if certificate:
+ certificate = base64.b64encode(certificate)
+ signature.certificate = b'\n'.join(
+ [b'-----BEGIN CERTIFICATE-----'] +
+ [certificate[i:i + 64]
+ for i in range(0, len(certificate), 64)] +
+ [b'-----END CERTIFICATE-----'])
diff --git a/pskc/signature.py b/pskc/signature.py
new file mode 100644
index 0000000..31c3ab0
--- /dev/null
+++ b/pskc/signature.py
@@ -0,0 +1,68 @@
+# signature.py - module for handling signed XML files
+# coding: utf-8
+#
+# Copyright (C) 2017 Arthur de Jong
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+"""Module for handling signed PSKC files.
+
+This module defines a Signature class that handles the signature checking,
+keys and certificates.
+"""
+
+
+class Signature(object):
+ """Class for handling signature checking of the PSKC file.
+
+ Instances of this class provide the following properties:
+
+ is_signed: boolean to indicate whether a signature is present
+ algorithm: identifier of the signing algorithm used
+ canonicalization_method: identifier of the XML canonicalization used
+ digest_algorithm: algorithm used for creating the hash
+ issuer: issuer of the certificate
+ serial: serial number of the certificate
+ certificate: the certificate that is embedded in the signature
+ """
+
+ def __init__(self, pskc):
+ self.pskc = pskc
+ self._algorithm = None
+ self.canonicalization_method = None
+ self.digest_algorithm = None
+ self.issuer = None
+ self.serial = None
+ self.certificate = None
+
+ @property
+ def is_signed(self):
+ """Test whether the PSKC file contains a signature (not whether the
+ signature is valid)."""
+ return bool(
+ self.algorithm or self.canonicalization_method or
+ self.digest_algorithm or self.issuer or self.certificate)
+
+ @property
+ def algorithm(self):
+ """Provide the signing algorithm used."""
+ if self._algorithm:
+ return self._algorithm
+
+ @algorithm.setter
+ def algorithm(self, value):
+ from pskc.algorithms import normalise_algorithm
+ self._algorithm = normalise_algorithm(value)
diff --git a/tests/test_draft_ietf_keyprov_pskc_02.doctest b/tests/test_draft_ietf_keyprov_pskc_02.doctest
index 7a039d5..63b3040 100644
--- a/tests/test_draft_ietf_keyprov_pskc_02.doctest
+++ b/tests/test_draft_ietf_keyprov_pskc_02.doctest
@@ -250,6 +250,18 @@ signature to sign the PSKC file. Note that python-pskc currently does not yet
support checking this signature so this test is very limited.
>>> pskc = PSKC('tests/draft-ietf-keyprov-pskc-02/figure8.pskcxml')
+>>> pskc.signature.is_signed
+True
+>>> pskc.signature.canonicalization_method
+'http://www.w3.org/2001/10/xml-exc-c14n#'
+>>> pskc.signature.algorithm
+'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
+>>> pskc.signature.digest_algorithm
+'http://www.w3.org/2000/09/xmldsig#sha1'
+>>> pskc.signature.issuer
+'CN=Example.com,C=US'
+>>> pskc.signature.serial
+'12345678'
>>> key = pskc.keys[0]
>>> key.manufacturer
'TokenVendorAcme'
diff --git a/tests/test_rfc6030.doctest b/tests/test_rfc6030.doctest
index e872a95..a3438ac 100644
--- a/tests/test_rfc6030.doctest
+++ b/tests/test_rfc6030.doctest
@@ -1,6 +1,6 @@
test_rfc6030.doctest - test for examples from RFC 6030
-Copyright (C) 2014-2016 Arthur de Jong
+Copyright (C) 2014-2017 Arthur de Jong
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -245,6 +245,18 @@ seen in figure 8 of RFC 6030. Note that python-pskc currently does not yet
support checking this signature so this test is very limited.
>>> pskc = PSKC('tests/rfc6030/figure9.pskcxml')
+>>> pskc.signature.is_signed
+True
+>>> pskc.signature.algorithm
+'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
+>>> pskc.signature.canonicalization_method
+'http://www.w3.org/2001/10/xml-exc-c14n#'
+>>> pskc.signature.digest_algorithm
+'http://www.w3.org/2000/09/xmldsig#sha1'
+>>> pskc.signature.issuer
+'CN=Example.com,C=US'
+>>> pskc.signature.serial
+'12345678'
>>> key = pskc.keys[0]
>>> key.manufacturer
'TokenVendorAcme'