diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2017-09-22 11:53:19 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2017-12-27 19:04:26 +0100 |
commit | ea503d6590e3a3ede8e119da3887d8543731cf9a (patch) | |
tree | 8d081cf6dbe5fd33a3d821b94cc0343aad96262d | |
parent | fcc6cdb0320cdae1206f2f231c2f5bca56b9b847 (diff) |
Implement basic parsing of signature properties
-rw-r--r-- | pskc/__init__.py | 2 | ||||
-rw-r--r-- | pskc/parser.py | 30 | ||||
-rw-r--r-- | pskc/signature.py | 68 | ||||
-rw-r--r-- | tests/test_draft_ietf_keyprov_pskc_02.doctest | 12 | ||||
-rw-r--r-- | tests/test_rfc6030.doctest | 14 |
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' |