From 17e2f3ba515173a89058382ccc210074071f2ef4 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 12:57:09 +0100 Subject: [PATCH 01/21] feat: fail if no private key is provided --- pymdoccbor/mdoc/exceptions.py | 2 ++ pymdoccbor/mdoc/issuer.py | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 pymdoccbor/mdoc/exceptions.py diff --git a/pymdoccbor/mdoc/exceptions.py b/pymdoccbor/mdoc/exceptions.py new file mode 100644 index 0000000..80582b5 --- /dev/null +++ b/pymdoccbor/mdoc/exceptions.py @@ -0,0 +1,2 @@ +class MissingPrivateKey(Exception): + pass \ No newline at end of file diff --git a/pymdoccbor/mdoc/issuer.py b/pymdoccbor/mdoc/issuer.py index bb86e41..4247b96 100644 --- a/pymdoccbor/mdoc/issuer.py +++ b/pymdoccbor/mdoc/issuer.py @@ -6,15 +6,20 @@ from typing import Union from pymdoccbor.mso.issuer import MsoIssuer +from pymdoccbor.mdoc.exceptions import MissingPrivateKey logger = logging.getLogger('pymdoccbor') class MdocCborIssuer: - def __init__(self, private_key: Union[dict, CoseKey] = {}): + def __init__(self, private_key: Union[dict, CoseKey]): self.version: str = '1.0' self.status: int = 0 + + if not private_key: + raise MissingPrivateKey("You must provide a private key") + if private_key and isinstance(private_key, dict): self.private_key = CoseKey.from_dict(private_key) From 78931b5057f29be7efbd39aa949b650832d7e281 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 12:57:40 +0100 Subject: [PATCH 02/21] feat: handle multiple documents --- pymdoccbor/mdoc/issuer.py | 62 +++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/pymdoccbor/mdoc/issuer.py b/pymdoccbor/mdoc/issuer.py index 4247b96..5795616 100644 --- a/pymdoccbor/mdoc/issuer.py +++ b/pymdoccbor/mdoc/issuer.py @@ -27,10 +27,10 @@ def __init__(self, private_key: Union[dict, CoseKey]): def new( self, - data: dict, + data: dict | list[dict], devicekeyinfo: Union[dict, CoseKey], - doctype: str - ): + doctype: str | None = None + ) -> dict: """ create a new mdoc with signed mso """ @@ -39,35 +39,41 @@ def new( else: devicekeyinfo: CoseKey = devicekeyinfo - msoi = MsoIssuer( - data=data, - private_key=self.private_key - ) + if isinstance(data, dict): + data = [{"doctype": doctype, "data": data}] - mso = msoi.sign() + documents = [] + + for doc in data: + msoi = MsoIssuer( + data=doc["data"], + private_key=self.private_key + ) + + mso = msoi.sign() + + document = { + 'docType': doc["doctype"], # 'org.iso.18013.5.1.mDL' + 'issuerSigned': { + "nameSpaces": { + ns: [ + cbor2.CBORTag(24, value={k: v}) for k, v in dgst.items() + ] + for ns, dgst in msoi.disclosure_map.items() + }, + "issuerAuth": mso.encode() + }, + # this is required during the presentation. + # 'deviceSigned': { + # # TODO + # } + } + + documents.append(document) - # TODO: for now just a single document, it would be trivial having - # also multiple but for now I don't have use cases for this self.signed = { 'version': self.version, - 'documents': [ - { - 'docType': doctype, # 'org.iso.18013.5.1.mDL' - 'issuerSigned': { - "nameSpaces": { - ns: [ - cbor2.CBORTag(24, value={k: v}) for k, v in dgst.items() - ] - for ns, dgst in msoi.disclosure_map.items() - }, - "issuerAuth": mso.encode() - }, - # this is required during the presentation. - # 'deviceSigned': { - # # TODO - # } - } - ], + 'documents': documents, 'status': self.status } return self.signed From 7c8e2845dfb79145e594af3ccac502b1fba24b2e Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 12:58:36 +0100 Subject: [PATCH 03/21] chore: dummy micov doc --- pymdoccbor/tests/micov_data.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 pymdoccbor/tests/micov_data.py diff --git a/pymdoccbor/tests/micov_data.py b/pymdoccbor/tests/micov_data.py new file mode 100644 index 0000000..c219f74 --- /dev/null +++ b/pymdoccbor/tests/micov_data.py @@ -0,0 +1,23 @@ +MICOV_DATA = { + "org.micov.medical.1":{ + "last_name": "Rossi", + "given_name": "Mario", + "birth_date": "1922-03-13", + "PersonId_nic": { + "PersonIdNumber": "1234567890", + "PersonIdType": "nic", + "PersonIdIS": "IT", + }, + "sex": 1, + "VPInfo_COVID-19_1": { + "VaccineProphylaxis": "", + "VaccMedicinalProd": "Moderna", + "VaccMktAuthHolder": "Moderna", + "VaccDoseNumber": "2/2", + "VaccAdmDate": "2021-01-01", + "VaccCountry": "IT", + }, + "CertIssuer": "Italian Ministry of Health", + "CertId": "1234567890", + } +} \ No newline at end of file From b8f398b8870b291c43936987c0d78b37f369b313 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 12:59:11 +0100 Subject: [PATCH 04/21] test: created unit tests for MdocCborIssuer --- pymdoccbor/tests/test_mdoc_issuer.py | 65 ++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 pymdoccbor/tests/test_mdoc_issuer.py diff --git a/pymdoccbor/tests/test_mdoc_issuer.py b/pymdoccbor/tests/test_mdoc_issuer.py new file mode 100644 index 0000000..c9cbc7d --- /dev/null +++ b/pymdoccbor/tests/test_mdoc_issuer.py @@ -0,0 +1,65 @@ +import os +from pymdoccbor.mdoc.issuer import MdocCborIssuer +from pymdoccbor.tests.micov_data import MICOV_DATA +from pymdoccbor.tests.pid_data import PID_DATA + + +PKEY = { + 'KTY': 'EC2', + 'CURVE': 'P_256', + 'ALG': 'ES256', + 'D': os.urandom(32), + 'KID': b"demo-kid" +} + +mdoc = MdocCborIssuer(PKEY) + +def test_MdocCborIssuer_creation(): + assert mdoc.version == '1.0' + assert mdoc.status == 0 + +def test_mdoc_without_private_key_must_fail(): + try: + MdocCborIssuer(None) + except Exception as e: + assert str(e) == "You must provide a private key" + +def test_MdocCborIssuer_new_single(): + mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" + ) + assert mdoc.signed['version'] == '1.0' + assert mdoc.signed['status'] == 0 + assert mdoc.signed['documents'][0]['docType'] == 'org.micov.medical.1' + assert mdoc.signed['documents'][0]['issuerSigned']['nameSpaces']['org.micov.medical.1'][0].tag == 24 + +def test_MdocCborIssuer_new_multiple(): + micov_data = {"doctype": "org.micov.medical.1", "data": MICOV_DATA} + pid_data = {"doctype": "eu.europa.ec.eudiw.pid.1", "data": PID_DATA} + + mdoc.new( + data=[micov_data, pid_data], + devicekeyinfo=PKEY # TODO + ) + assert mdoc.signed['version'] == '1.0' + assert mdoc.signed['status'] == 0 + assert mdoc.signed['documents'][0]['docType'] == 'org.micov.medical.1' + assert mdoc.signed['documents'][0]['issuerSigned']['nameSpaces']['org.micov.medical.1'][0].tag == 24 + assert mdoc.signed['documents'][1]['docType'] == 'eu.europa.ec.eudiw.pid.1' + assert mdoc.signed['documents'][1]['issuerSigned']['nameSpaces']['eu.europa.ec.eudiw.pid.1'][0].tag == 24 + +def test_MdocCborIssuer_dump(): + dump = mdoc.dump() + + assert dump + assert isinstance(dump, bytes) + assert len(dump) > 0 + +def test_MdocCborIssuer_dumps(): + dumps = mdoc.dumps() + + assert dumps + assert isinstance(dumps, bytes) + assert len(dumps) > 0 \ No newline at end of file From 616a426cfdd615a38335d5e909a505f19e1d8a0e Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 14:24:45 +0100 Subject: [PATCH 05/21] feat: added docstring --- pymdoccbor/mdoc/issuer.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/pymdoccbor/mdoc/issuer.py b/pymdoccbor/mdoc/issuer.py index 5795616..ccf8daa 100644 --- a/pymdoccbor/mdoc/issuer.py +++ b/pymdoccbor/mdoc/issuer.py @@ -12,8 +12,19 @@ class MdocCborIssuer: + """ + MdocCborIssuer helper class to create a new mdoc + """ def __init__(self, private_key: Union[dict, CoseKey]): + """ + Create a new MdocCborIssuer instance + + :param private_key: the private key to sign the mdoc + :type private_key: dict | CoseKey + + :raises MissingPrivateKey: if no private key is provided + """ self.version: str = '1.0' self.status: int = 0 @@ -33,6 +44,19 @@ def new( ) -> dict: """ create a new mdoc with signed mso + + :param data: the data to sign + Can be a dict, representing the single document, or a list of dicts containg the doctype and the data + Example: + {doctype: "org.iso.18013.5.1.mDL", data: {...}} + :type data: dict | list[dict] + :param devicekeyinfo: the device key info + :type devicekeyinfo: dict | CoseKey + :param doctype: the document type (optional if data is a list) + :type doctype: str | None + + :return: the signed mdoc + :rtype: dict """ if isinstance(devicekeyinfo, dict): devicekeyinfo = CoseKey.from_dict(devicekeyinfo) @@ -80,12 +104,18 @@ def new( def dump(self): """ - returns bytes + Returns the signed mdoc in CBOR format + + :return: the signed mdoc in CBOR format + :rtype: bytes """ return cbor2.dumps(self.signed) def dumps(self): """ - returns AF binary repr + Returns the signed mdoc in AF binary repr + + :return: the signed mdoc in AF binary repr + :rtype: bytes """ return binascii.hexlify(cbor2.dumps(self.signed)) From ee5354cebdb53e43cb0cde1d0a67491b2ed63d7e Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 15:54:56 +0100 Subject: [PATCH 06/21] feat: handle missing parameters --- pymdoccbor/mdoc/exceptions.py | 6 ++++++ pymdoccbor/mdoc/verifier.py | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/pymdoccbor/mdoc/exceptions.py b/pymdoccbor/mdoc/exceptions.py index 80582b5..35cd1f5 100644 --- a/pymdoccbor/mdoc/exceptions.py +++ b/pymdoccbor/mdoc/exceptions.py @@ -1,2 +1,8 @@ class MissingPrivateKey(Exception): + pass + +class NoDocumentTypeProvided(Exception): + pass + +class NoSignedDocumentProvided(Exception): pass \ No newline at end of file diff --git a/pymdoccbor/mdoc/verifier.py b/pymdoccbor/mdoc/verifier.py index 20862c5..25e8e4d 100644 --- a/pymdoccbor/mdoc/verifier.py +++ b/pymdoccbor/mdoc/verifier.py @@ -6,6 +6,7 @@ from pymdoccbor.exceptions import InvalidMdoc from pymdoccbor.mdoc.issuersigned import IssuerSigned +from pymdoccbor.mdoc.exceptions import NoDocumentTypeProvided, NoSignedDocumentProvided logger = logging.getLogger('pymdoccbor') @@ -17,6 +18,12 @@ class MobileDocument: } def __init__(self, docType: str, issuerSigned: dict, deviceSigned: dict = {}): + if not docType: + raise NoDocumentTypeProvided("You must provide a document type") + + if not issuerSigned: + raise NoSignedDocumentProvided("You must provide a signed document") + self.doctype: str = docType # eg: 'org.iso.18013.5.1.mDL' self.issuersigned: List[IssuerSigned] = IssuerSigned(**issuerSigned) self.is_valid = False From e9d76aaf2c130cd799708b24c249f08d9b3f6b2f Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 15:56:22 +0100 Subject: [PATCH 07/21] fix: fix type --- pymdoccbor/mdoc/verifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymdoccbor/mdoc/verifier.py b/pymdoccbor/mdoc/verifier.py index 25e8e4d..3b84aa2 100644 --- a/pymdoccbor/mdoc/verifier.py +++ b/pymdoccbor/mdoc/verifier.py @@ -25,7 +25,7 @@ def __init__(self, docType: str, issuerSigned: dict, deviceSigned: dict = {}): raise NoSignedDocumentProvided("You must provide a signed document") self.doctype: str = docType # eg: 'org.iso.18013.5.1.mDL' - self.issuersigned: List[IssuerSigned] = IssuerSigned(**issuerSigned) + self.issuersigned: IssuerSigned = IssuerSigned(**issuerSigned) self.is_valid = False # TODO From 7b84b453055a32d74c9dc0ab5d6893997b31257e Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 15:56:57 +0100 Subject: [PATCH 08/21] docs: added docstring for MobileDocument --- pymdoccbor/mdoc/verifier.py | 45 +++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/pymdoccbor/mdoc/verifier.py b/pymdoccbor/mdoc/verifier.py index 3b84aa2..d9ddf51 100644 --- a/pymdoccbor/mdoc/verifier.py +++ b/pymdoccbor/mdoc/verifier.py @@ -12,12 +12,30 @@ class MobileDocument: + """ + MobileDocument helper class to verify a mdoc + """ + _states = { True: "valid", False: "failed", } def __init__(self, docType: str, issuerSigned: dict, deviceSigned: dict = {}): + """ + Create a new MobileDocument instance + + :param docType: the document type + :type docType: str + :param issuerSigned: the issuer signed data + :type issuerSigned: dict + :param deviceSigned: the device signed data + :type deviceSigned: dict + + :raises NoDocumentTypeProvided: if no document type is provided + :raises NoSignedDocumentProvided: if no signed document is provided + """ + if not docType: raise NoDocumentTypeProvided("You must provide a document type") @@ -32,6 +50,13 @@ def __init__(self, docType: str, issuerSigned: dict, deviceSigned: dict = {}): self.devicesigned: dict = deviceSigned def dump(self) -> dict: + """ + Returns a dict representation of the document + + :return: the document as dict + :rtype: dict + """ + return { 'docType': self.doctype, 'issuerSigned': self.issuersigned.dump() @@ -39,23 +64,35 @@ def dump(self) -> dict: def dumps(self) -> str: """ - returns an AF binary repr of the document + Returns an AF binary repr of the document + + :return: the document as AF binary + :rtype: str """ return binascii.hexlify(self.dump()) def dump(self) -> bytes: """ - returns bytes + Returns a CBOR repr of the document + + :return: the document as CBOR + :rtype: bytes """ return cbor2.dumps( cbor2.CBORTag(24, value={ 'docType': self.doctype, 'issuerSigned': self.issuersigned.dumps() - } - ) + }) ) def verify(self) -> bool: + """ + Verify the document signature + + :return: True if valid, False otherwise + :rtype: bool + """ + self.is_valid = self.issuersigned.issuer_auth.verify_signature() return self.is_valid From f3d5f81ca8ecb2cfaf73f0d9e9530d7d55bdbbf3 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 15:57:35 +0100 Subject: [PATCH 09/21] docs: added docstring --- pymdoccbor/mso/issuer.py | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/pymdoccbor/mso/issuer.py b/pymdoccbor/mso/issuer.py index 3fc33e9..3e0f226 100644 --- a/pymdoccbor/mso/issuer.py +++ b/pymdoccbor/mso/issuer.py @@ -20,7 +20,7 @@ class MsoIssuer(MsoX509Fabric): """ - + MsoIssuer helper class to create a new mso """ def __init__( @@ -29,6 +29,18 @@ def __init__( private_key: Union[dict, CoseKey], digest_alg: str = settings.PYMDOC_HASHALG ): + """ + Create a new MsoIssuer instance + + :param data: the data to sign + :type data: dict + :param private_key: the private key to sign the mso + :type private_key: dict | CoseKey + :param digest_alg: the digest algorithm to use + :type digest_alg: str + + :raises MsoPrivateKeyRequired: if no private key is provided + """ if private_key and isinstance(private_key, dict): self.private_key = CoseKey.from_dict(private_key) @@ -90,17 +102,36 @@ def __init__( digest_cnt += 1 - def format_datetime_repr(self, dt: datetime.datetime): + def format_datetime_repr(self, dt: datetime.datetime) -> str: + """ + Format a datetime object to a string representation + + :param dt: the datetime object + :type dt: datetime.datetime + + :return: the string representation + :rtype: str + """ return dt.isoformat().split('.')[0] + 'Z' def sign( self, device_key: Union[dict, None] = None, valid_from: Union[None, datetime.datetime] = None, - doctype: str = None + doctype: str | None = None ) -> Sign1Message: """ - sign a mso and returns it + Sign a mso and returns it + + :param device_key: the device key info + :type device_key: dict | None + :param valid_from: the validity start date + :type valid_from: datetime.datetime | None + :param doctype: the document type + :type doctype: str + + :return: the signed mso + :rtype: Sign1Message """ utcnow = datetime.datetime.utcnow() if settings.PYMDOC_EXP_DELTA_HOURS: From e067e4fc8a1b186639b0aa4713b655728c153d34 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 15:57:59 +0100 Subject: [PATCH 10/21] test: added tests for mso --- pymdoccbor/tests/test_mso_issuer.py | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 pymdoccbor/tests/test_mso_issuer.py diff --git a/pymdoccbor/tests/test_mso_issuer.py b/pymdoccbor/tests/test_mso_issuer.py new file mode 100644 index 0000000..3e926b2 --- /dev/null +++ b/pymdoccbor/tests/test_mso_issuer.py @@ -0,0 +1,40 @@ +import os +from pycose.messages import CoseMessage +from pymdoccbor.mso.issuer import MsoIssuer +from pymdoccbor.tests.micov_data import MICOV_DATA + +PKEY = { + 'KTY': 'EC2', + 'CURVE': 'P_256', + 'ALG': 'ES256', + 'D': os.urandom(32), + 'KID': b"demo-kid" +} + +def test_mso_issuer_fail(): + try: + MsoIssuer(None, None) + except Exception as e: + assert str(e) == "MSO Writer requires a valid private key" + +def test_mso_issuer_creation(): + msoi = MsoIssuer( + data=MICOV_DATA, + private_key=PKEY + ) + + assert msoi.private_key + assert msoi.public_key + assert msoi.data + assert msoi.hash_map + assert list(msoi.hash_map.keys())[0] == 'org.micov.medical.1' + assert msoi.disclosure_map['org.micov.medical.1'] + +def test_mso_issuer_sign(): + msoi = MsoIssuer( + data=MICOV_DATA, + private_key=PKEY + ) + + mso = msoi.sign() + assert isinstance(mso, CoseMessage) From 1aabea45f667cafdb56390687e729af6f28c606c Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 16:35:19 +0100 Subject: [PATCH 11/21] feat: fail if issuer auth is missing --- pymdoccbor/mdoc/exceptions.py | 3 +++ pymdoccbor/mdoc/issuersigned.py | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pymdoccbor/mdoc/exceptions.py b/pymdoccbor/mdoc/exceptions.py index 35cd1f5..0e12122 100644 --- a/pymdoccbor/mdoc/exceptions.py +++ b/pymdoccbor/mdoc/exceptions.py @@ -5,4 +5,7 @@ class NoDocumentTypeProvided(Exception): pass class NoSignedDocumentProvided(Exception): + pass + +class MissingIssuerAuth(Exception): pass \ No newline at end of file diff --git a/pymdoccbor/mdoc/issuersigned.py b/pymdoccbor/mdoc/issuersigned.py index 1c39b84..626d6c0 100644 --- a/pymdoccbor/mdoc/issuersigned.py +++ b/pymdoccbor/mdoc/issuersigned.py @@ -25,7 +25,9 @@ class IssuerSigned: def __init__(self, nameSpaces: dict, issuerAuth: Union[dict, bytes]): self.namespaces: dict = nameSpaces - # if isinstance(ia, dict): + if not issuerAuth: + raise MissingIssuerAuth("issuerAuth must be provided") + self.issuer_auth = MsoVerifier(issuerAuth) def dump(self) -> dict: From 4c6936950855a37f26a81550cd23685934179f43 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 16:35:39 +0100 Subject: [PATCH 12/21] docs: amplied docstring --- pymdoccbor/mdoc/issuersigned.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pymdoccbor/mdoc/issuersigned.py b/pymdoccbor/mdoc/issuersigned.py index 626d6c0..f50fd00 100644 --- a/pymdoccbor/mdoc/issuersigned.py +++ b/pymdoccbor/mdoc/issuersigned.py @@ -2,10 +2,13 @@ from typing import Union from pymdoccbor.mso.verifier import MsoVerifier +from pymdoccbor.mdoc.exceptions import MissingIssuerAuth class IssuerSigned: """ + IssuerSigned helper class to handle issuer signed data + nameSpaces provides the definition within which the data elements of the document are defined. A document may have multiple nameSpaces. @@ -22,7 +25,17 @@ class IssuerSigned: ] """ - def __init__(self, nameSpaces: dict, issuerAuth: Union[dict, bytes]): + def __init__(self, nameSpaces: dict, issuerAuth: Union[dict, bytes]) -> None: + """ + Create a new IssuerSigned instance + + :param nameSpaces: the namespaces + :type nameSpaces: dict + :param issuerAuth: the issuer auth + :type issuerAuth: dict | bytes + + :raises MissingIssuerAuth: if no issuer auth is provided + """ self.namespaces: dict = nameSpaces if not issuerAuth: @@ -31,12 +44,24 @@ def __init__(self, nameSpaces: dict, issuerAuth: Union[dict, bytes]): self.issuer_auth = MsoVerifier(issuerAuth) def dump(self) -> dict: + """ + Returns a dict representation of the issuer signed data + + :return: the issuer signed data as dict + :rtype: dict + """ return { 'nameSpaces': self.namespaces, 'issuerAuth': self.issuer_auth } - def dumps(self) -> dict: + def dumps(self) -> bytes: + """ + Returns a CBOR representation of the issuer signed data + + :return: the issuer signed data as CBOR + :rtype: bytes + """ return cbor2.dumps( { 'nameSpaces': self.namespaces, From 20db73a1c7e993ea0771a04a500e0f117b033bae Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 16:35:59 +0100 Subject: [PATCH 13/21] test: issuer signed tests --- pymdoccbor/tests/test_issuer_signed.py | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 pymdoccbor/tests/test_issuer_signed.py diff --git a/pymdoccbor/tests/test_issuer_signed.py b/pymdoccbor/tests/test_issuer_signed.py new file mode 100644 index 0000000..7100bfa --- /dev/null +++ b/pymdoccbor/tests/test_issuer_signed.py @@ -0,0 +1,69 @@ +import os +from pymdoccbor.mdoc.issuersigned import IssuerSigned +from pymdoccbor.mdoc.issuer import MdocCborIssuer +from pymdoccbor.tests.micov_data import MICOV_DATA + +PKEY = { + 'KTY': 'EC2', + 'CURVE': 'P_256', + 'ALG': 'ES256', + 'D': os.urandom(32), + 'KID': b"demo-kid" +} + +issuer_signed = None + +def test_issuer_signed_fail(): + try: + IssuerSigned(None, None) + except Exception as e: + assert str(e) == "issuerAuth must be provided" + +def test_issuer_signed_creation(): + issued_doc = MdocCborIssuer(PKEY) + issued_doc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, + doctype="org.micov.medical.1" + ) + + issuerAuth = issued_doc.signed["documents"][0]["issuerSigned"] + + issuer_signed = IssuerSigned(**issuerAuth) + + assert issuer_signed.namespaces + assert issuer_signed.issuer_auth + +def test_issuer_signed_dump(): + issued_doc = MdocCborIssuer(PKEY) + issued_doc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, + doctype="org.micov.medical.1" + ) + + issuerAuth = issued_doc.signed["documents"][0]["issuerSigned"] + + issuer_signed = IssuerSigned(**issuerAuth) + + dump = issuer_signed.dump() + assert dump + assert dump["nameSpaces"] == issuer_signed.namespaces + assert dump["issuerAuth"] == issuer_signed.issuer_auth + +def test_issuer_signed_dumps(): + issued_doc = MdocCborIssuer(PKEY) + issued_doc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, + doctype="org.micov.medical.1" + ) + + issuerAuth = issued_doc.signed["documents"][0]["issuerSigned"] + + issuer_signed = IssuerSigned(**issuerAuth) + + dumps = issuer_signed.dumps() + assert dumps + assert isinstance(dumps, bytes) + assert len(dumps) > 0 \ No newline at end of file From c447bd6e0a073e9ca6069283b3ac5f5278e5aa30 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 16:48:45 +0100 Subject: [PATCH 14/21] docs: amplied docstring --- pymdoccbor/mso/verifier.py | 57 ++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/pymdoccbor/mso/verifier.py b/pymdoccbor/mso/verifier.py index cd6284f..aa9b62d 100644 --- a/pymdoccbor/mso/verifier.py +++ b/pymdoccbor/mso/verifier.py @@ -5,8 +5,6 @@ from pycose.keys import CoseKey, EC2Key from pycose.messages import Sign1Message -from typing import Optional - from pymdoccbor.exceptions import ( MsoX509ChainNotFound, UnsupportedMsoDataFormat @@ -20,6 +18,8 @@ class MsoVerifier: """ + MsoVerifier helper class to verify a mso + Parameters data: CBOR TAG 24 @@ -31,7 +31,15 @@ class MsoVerifier: structure as defined in RFC 8152. """ - def __init__(self, data: cbor2.CBORTag): + def __init__(self, data: cbor2.CBORTag) -> None: + """ + Create a new MsoParser instance + + :param data: the data to verify + :type data: cbor2.CBORTag + + :raises UnsupportedMsoDataFormat: if the data format is not supported + """ self._data = data # not used if isinstance(self._data, bytes): @@ -44,23 +52,35 @@ def __init__(self, data: cbor2.CBORTag): f"MsoParser only supports raw bytes and list, a {type(data)} was provided" ) - self.object.key: Optional[CoseKey, None] = None + self.object.key: CoseKey | None = None self.public_key: cryptography.hazmat.backends.openssl.ec._EllipticCurvePublicKey = None self.x509_certificates: list = [] @property - def payload_as_cbor(self): + def payload_as_cbor(self) -> cbor2.CBORTag: """ - return the decoded payload + Return the decoded payload + + :return: the decoded payload + :rtype: cbor2.CBORTag """ return cbor2.loads(self.object.payload) @property - def payload_as_raw(self): + def payload_as_raw(self) -> bytes: + """ + Return the raw payload + + :return: the raw payload + :rtype: bytes + """ return self.object.payload @property - def payload_as_dict(self): + def payload_as_dict(self) -> dict: + """ + Return the payload as dict + """ return cbor2.loads( cbor2.loads(self.object.payload).value ) @@ -68,8 +88,13 @@ def payload_as_dict(self): @property def raw_public_keys(self) -> bytes: """ - it returns the public key extract from x509 certificates - looking to both phdr and uhdr + It returns the public key extract from x509 certificates + looking to both phdr and uhdr + + :raises MsoX509ChainNotFound: if no valid x509 certificate is found + + :return: the raw public key + :rtype: bytes """ _mixed_heads = self.object.phdr.items() | self.object.uhdr.items() for h, v in _mixed_heads: @@ -81,7 +106,7 @@ def raw_public_keys(self) -> bytes: "in this MSO." ) - def attest_public_key(self): + def attest_public_key(self) -> None: logger.warning( "TODO: in next releases. " "The certificate is to be considered as untrusted, this release " @@ -89,7 +114,10 @@ def attest_public_key(self): "python certvalidator or cryptography for that." ) - def load_public_key(self): + def load_public_key(self) -> None: + """ + Load the public key from the x509 certificate + """ self.attest_public_key() @@ -109,7 +137,12 @@ def load_public_key(self): self.object.key = key def verify_signature(self) -> bool: + """ + Verify the signature + :return: True if valid, False otherwise + :rtype: bool + """ if not self.object.key: self.load_public_key() From 01cfa1de92611855ac37d794c48a40a0b236cdf2 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 17:22:21 +0100 Subject: [PATCH 15/21] fix: test refactoring --- ..._mdoc_issuer.py => test_03_mdoc_issuer.py} | 0 ...uer_signed.py => test_04_issuer_signed.py} | 39 ++++++------------- ...st_mso_issuer.py => test_06_mso_issuer.py} | 0 3 files changed, 11 insertions(+), 28 deletions(-) rename pymdoccbor/tests/{test_mdoc_issuer.py => test_03_mdoc_issuer.py} (100%) rename pymdoccbor/tests/{test_issuer_signed.py => test_04_issuer_signed.py} (57%) rename pymdoccbor/tests/{test_mso_issuer.py => test_06_mso_issuer.py} (100%) diff --git a/pymdoccbor/tests/test_mdoc_issuer.py b/pymdoccbor/tests/test_03_mdoc_issuer.py similarity index 100% rename from pymdoccbor/tests/test_mdoc_issuer.py rename to pymdoccbor/tests/test_03_mdoc_issuer.py diff --git a/pymdoccbor/tests/test_issuer_signed.py b/pymdoccbor/tests/test_04_issuer_signed.py similarity index 57% rename from pymdoccbor/tests/test_issuer_signed.py rename to pymdoccbor/tests/test_04_issuer_signed.py index 7100bfa..b11be83 100644 --- a/pymdoccbor/tests/test_issuer_signed.py +++ b/pymdoccbor/tests/test_04_issuer_signed.py @@ -2,6 +2,7 @@ from pymdoccbor.mdoc.issuersigned import IssuerSigned from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA +from pymdoccbor.tests.test_03_mdoc_issuer import mdoc PKEY = { 'KTY': 'EC2', @@ -11,7 +12,14 @@ 'KID': b"demo-kid" } -issuer_signed = None +mdoc = MdocCborIssuer(PKEY) +mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" +) +issuerAuth = mdoc.signed["documents"][0]["issuerSigned"] +issuer_signed = IssuerSigned(**issuerAuth) def test_issuer_signed_fail(): try: @@ -20,29 +28,11 @@ def test_issuer_signed_fail(): assert str(e) == "issuerAuth must be provided" def test_issuer_signed_creation(): - issued_doc = MdocCborIssuer(PKEY) - issued_doc.new( - data=MICOV_DATA, - devicekeyinfo=PKEY, - doctype="org.micov.medical.1" - ) - - issuerAuth = issued_doc.signed["documents"][0]["issuerSigned"] - - issuer_signed = IssuerSigned(**issuerAuth) - assert issuer_signed.namespaces assert issuer_signed.issuer_auth def test_issuer_signed_dump(): - issued_doc = MdocCborIssuer(PKEY) - issued_doc.new( - data=MICOV_DATA, - devicekeyinfo=PKEY, - doctype="org.micov.medical.1" - ) - - issuerAuth = issued_doc.signed["documents"][0]["issuerSigned"] + issuerAuth = mdoc.signed["documents"][0]["issuerSigned"] issuer_signed = IssuerSigned(**issuerAuth) @@ -52,14 +42,7 @@ def test_issuer_signed_dump(): assert dump["issuerAuth"] == issuer_signed.issuer_auth def test_issuer_signed_dumps(): - issued_doc = MdocCborIssuer(PKEY) - issued_doc.new( - data=MICOV_DATA, - devicekeyinfo=PKEY, - doctype="org.micov.medical.1" - ) - - issuerAuth = issued_doc.signed["documents"][0]["issuerSigned"] + issuerAuth = mdoc.signed["documents"][0]["issuerSigned"] issuer_signed = IssuerSigned(**issuerAuth) diff --git a/pymdoccbor/tests/test_mso_issuer.py b/pymdoccbor/tests/test_06_mso_issuer.py similarity index 100% rename from pymdoccbor/tests/test_mso_issuer.py rename to pymdoccbor/tests/test_06_mso_issuer.py From e8686eed3e744d3401a2062a238dd6ea0d9a4a74 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 17:22:39 +0100 Subject: [PATCH 16/21] fix: fix docs --- pymdoccbor/mso/verifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pymdoccbor/mso/verifier.py b/pymdoccbor/mso/verifier.py index aa9b62d..7ccc4b8 100644 --- a/pymdoccbor/mso/verifier.py +++ b/pymdoccbor/mso/verifier.py @@ -57,12 +57,12 @@ def __init__(self, data: cbor2.CBORTag) -> None: self.x509_certificates: list = [] @property - def payload_as_cbor(self) -> cbor2.CBORTag: + def payload_as_cbor(self) -> dict: """ Return the decoded payload :return: the decoded payload - :rtype: cbor2.CBORTag + :rtype: dict """ return cbor2.loads(self.object.payload) From 0be45afa5a72e833f34eaec847ba30bb5ffb1101 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Fri, 26 Jan 2024 17:23:33 +0100 Subject: [PATCH 17/21] tests: added tests --- pymdoccbor/tests/test_05_mdoc_verifier.py | 62 ++++++++++++++++++++++ pymdoccbor/tests/test_07_mso_verifier.py | 63 +++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 pymdoccbor/tests/test_05_mdoc_verifier.py create mode 100644 pymdoccbor/tests/test_07_mso_verifier.py diff --git a/pymdoccbor/tests/test_05_mdoc_verifier.py b/pymdoccbor/tests/test_05_mdoc_verifier.py new file mode 100644 index 0000000..13c3eb3 --- /dev/null +++ b/pymdoccbor/tests/test_05_mdoc_verifier.py @@ -0,0 +1,62 @@ +import os +from pymdoccbor.mdoc.verifier import MobileDocument +from pymdoccbor.mdoc.issuer import MdocCborIssuer +from pymdoccbor.tests.micov_data import MICOV_DATA + +PKEY = { + 'KTY': 'EC2', + 'CURVE': 'P_256', + 'ALG': 'ES256', + 'D': os.urandom(32), + 'KID': b"demo-kid" +} + +mdoc = MdocCborIssuer(PKEY) +mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" +) + +def test_verifier_must_fail_document_type(): + try: + MobileDocument(None, None) + except Exception as e: + assert str(e) == "You must provide a document type" + +def test_verifier_must_fail_issuer_signed(): + try: + MobileDocument("org.micov.medical.1", None) + except Exception as e: + assert str(e) == "You must provide a signed document" + +def test_mobile_document(): + document = mdoc.signed["documents"][0] + doc = MobileDocument(**document) + + assert doc.doctype == "org.micov.medical.1" + assert doc.issuersigned + +def test_mobile_document_dump(): + document = mdoc.signed["documents"][0] + doc = MobileDocument(**document) + + dump = doc.dump() + assert dump + assert isinstance(dump, bytes) + assert len(dump) > 0 + +def test_mobile_document_dumps(): + document = mdoc.signed["documents"][0] + doc = MobileDocument(**document) + + dumps = doc.dumps() + assert dumps + assert isinstance(dumps, bytes) + assert len(dumps) > 0 + +def test_mobile_document_verify(): + document = mdoc.signed["documents"][0] + doc = MobileDocument(**document) + + #assert mdoc.verify() == True \ No newline at end of file diff --git a/pymdoccbor/tests/test_07_mso_verifier.py b/pymdoccbor/tests/test_07_mso_verifier.py new file mode 100644 index 0000000..3f2767c --- /dev/null +++ b/pymdoccbor/tests/test_07_mso_verifier.py @@ -0,0 +1,63 @@ +import os +from pymdoccbor.mso.verifier import MsoVerifier +from pymdoccbor.mdoc.issuer import MdocCborIssuer +from pymdoccbor.tests.micov_data import MICOV_DATA +from pycose.messages import CoseMessage + +PKEY = { + 'KTY': 'EC2', + 'CURVE': 'P_256', + 'ALG': 'ES256', + 'D': os.urandom(32), + 'KID': b"demo-kid" +} + +mdoc = MdocCborIssuer(PKEY) +mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" +) + +def test_mso_verifier_fail(): + try: + MsoVerifier(None) + except Exception as e: + assert str(e) == "MsoParser only supports raw bytes and list, a was provided" + +def test_mso_verifier_creation(): + issuerAuth = mdoc.signed["documents"][0]["issuerSigned"]["issuerAuth"] + + msov = MsoVerifier(issuerAuth) + + assert isinstance(msov.object, CoseMessage) + +def test_mso_verifier_verify_signatures(): + issuerAuth = mdoc.signed["documents"][0]["issuerSigned"]["issuerAuth"] + + msov = MsoVerifier(issuerAuth) + + assert msov.verify_signature() + +def test_mso_verifier_payload_as_cbor(): + issuerAuth = mdoc.signed["documents"][0]["issuerSigned"]["issuerAuth"] + + msov = MsoVerifier(issuerAuth) + + cbor = msov.payload_as_cbor + + assert cbor + assert cbor["version"] == "1.0" + assert cbor["digestAlgorithm"] == "sha256" + assert cbor["valueDigests"]["org.micov.medical.1"] + +def test_payload_as_raw(): + issuerAuth = mdoc.signed["documents"][0]["issuerSigned"]["issuerAuth"] + + msov = MsoVerifier(issuerAuth) + + raw = msov.payload_as_raw + + assert raw + assert isinstance(raw, bytes) + assert len(raw) > 0 \ No newline at end of file From 69352989ca186ea06d51a25982e62e032016996f Mon Sep 17 00:00:00 2001 From: PascalDR Date: Wed, 31 Jan 2024 14:54:16 +0100 Subject: [PATCH 18/21] feat: added support for EC2Key --- pymdoccbor/mdoc/issuer.py | 16 +++++++++++----- pymdoccbor/mso/issuer.py | 6 +++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/pymdoccbor/mdoc/issuer.py b/pymdoccbor/mdoc/issuer.py index ccf8daa..94169c6 100644 --- a/pymdoccbor/mdoc/issuer.py +++ b/pymdoccbor/mdoc/issuer.py @@ -2,7 +2,7 @@ import cbor2 import logging -from pycose.keys import CoseKey +from pycose.keys import CoseKey, EC2Key from typing import Union from pymdoccbor.mso.issuer import MsoIssuer @@ -16,7 +16,7 @@ class MdocCborIssuer: MdocCborIssuer helper class to create a new mdoc """ - def __init__(self, private_key: Union[dict, CoseKey]): + def __init__(self, private_key: Union[dict, EC2Key, CoseKey]): """ Create a new MdocCborIssuer instance @@ -28,11 +28,17 @@ def __init__(self, private_key: Union[dict, CoseKey]): self.version: str = '1.0' self.status: int = 0 - if not private_key: + if isinstance(private_key, dict): + self.private_key = CoseKey.from_dict(private_key) + elif isinstance(private_key, EC2Key): + ec2_encoded = private_key.encode() + ec2_decoded = CoseKey.decode(ec2_encoded) + self.private_key = ec2_decoded + elif isinstance(private_key, CoseKey): + self.private_key = private_key + else: raise MissingPrivateKey("You must provide a private key") - if private_key and isinstance(private_key, dict): - self.private_key = CoseKey.from_dict(private_key) self.signed :dict = {} diff --git a/pymdoccbor/mso/issuer.py b/pymdoccbor/mso/issuer.py index 3e0f226..94afe2e 100644 --- a/pymdoccbor/mso/issuer.py +++ b/pymdoccbor/mso/issuer.py @@ -26,7 +26,7 @@ class MsoIssuer(MsoX509Fabric): def __init__( self, data: dict, - private_key: Union[dict, CoseKey], + private_key: Union[dict, EC2Key, CoseKey], digest_alg: str = settings.PYMDOC_HASHALG ): """ @@ -48,6 +48,10 @@ def __init__( self.private_key.kid = str(uuid.uuid4()) elif private_key and isinstance(private_key, CoseKey): self.private_key = private_key + elif private_key and isinstance(private_key, EC2Key): + ec2_encoded = private_key.encode() + ec2_decoded = CoseKey.decode(ec2_encoded) + self.private_key = ec2_decoded else: raise MsoPrivateKeyRequired( "MSO Writer requires a valid private key" From f1f2889f4104683097e97533a97ca91872dbab3d Mon Sep 17 00:00:00 2001 From: PascalDR Date: Wed, 31 Jan 2024 14:54:46 +0100 Subject: [PATCH 19/21] test: fixed key generation --- pymdoccbor/tests/test_02_mdoc_issuer.py | 11 ++--------- pymdoccbor/tests/test_03_mdoc_issuer.py | 10 ++-------- pymdoccbor/tests/test_04_issuer_signed.py | 10 ++-------- pymdoccbor/tests/test_05_mdoc_verifier.py | 12 +++--------- pymdoccbor/tests/test_06_mso_issuer.py | 10 ++-------- pymdoccbor/tests/test_07_mso_verifier.py | 9 ++------- 6 files changed, 13 insertions(+), 49 deletions(-) diff --git a/pymdoccbor/tests/test_02_mdoc_issuer.py b/pymdoccbor/tests/test_02_mdoc_issuer.py index 2b7e758..076dd9b 100644 --- a/pymdoccbor/tests/test_02_mdoc_issuer.py +++ b/pymdoccbor/tests/test_02_mdoc_issuer.py @@ -2,21 +2,14 @@ import os from pycose.messages import Sign1Message - +from pycose.keys import EC2Key from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.mdoc.verifier import MdocCbor from pymdoccbor.mso.issuer import MsoIssuer from . pid_data import PID_DATA -PKEY = { - 'KTY': 'EC2', - 'CURVE': 'P_256', - 'ALG': 'ES256', - 'D': os.urandom(32), - 'KID': b"demo-kid" -} - +PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) def test_mso_writer(): msoi = MsoIssuer( diff --git a/pymdoccbor/tests/test_03_mdoc_issuer.py b/pymdoccbor/tests/test_03_mdoc_issuer.py index c9cbc7d..2c20e15 100644 --- a/pymdoccbor/tests/test_03_mdoc_issuer.py +++ b/pymdoccbor/tests/test_03_mdoc_issuer.py @@ -1,16 +1,10 @@ -import os +from pycose.keys import EC2Key from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA from pymdoccbor.tests.pid_data import PID_DATA -PKEY = { - 'KTY': 'EC2', - 'CURVE': 'P_256', - 'ALG': 'ES256', - 'D': os.urandom(32), - 'KID': b"demo-kid" -} +PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) mdoc = MdocCborIssuer(PKEY) diff --git a/pymdoccbor/tests/test_04_issuer_signed.py b/pymdoccbor/tests/test_04_issuer_signed.py index b11be83..24f974b 100644 --- a/pymdoccbor/tests/test_04_issuer_signed.py +++ b/pymdoccbor/tests/test_04_issuer_signed.py @@ -1,16 +1,10 @@ -import os +from pycose.keys import EC2Key from pymdoccbor.mdoc.issuersigned import IssuerSigned from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA from pymdoccbor.tests.test_03_mdoc_issuer import mdoc -PKEY = { - 'KTY': 'EC2', - 'CURVE': 'P_256', - 'ALG': 'ES256', - 'D': os.urandom(32), - 'KID': b"demo-kid" -} +PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) mdoc = MdocCborIssuer(PKEY) mdoc.new( diff --git a/pymdoccbor/tests/test_05_mdoc_verifier.py b/pymdoccbor/tests/test_05_mdoc_verifier.py index 13c3eb3..5f3eed1 100644 --- a/pymdoccbor/tests/test_05_mdoc_verifier.py +++ b/pymdoccbor/tests/test_05_mdoc_verifier.py @@ -1,15 +1,9 @@ -import os +from pycose.keys import EC2Key from pymdoccbor.mdoc.verifier import MobileDocument from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA -PKEY = { - 'KTY': 'EC2', - 'CURVE': 'P_256', - 'ALG': 'ES256', - 'D': os.urandom(32), - 'KID': b"demo-kid" -} +PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) mdoc = MdocCborIssuer(PKEY) mdoc.new( @@ -59,4 +53,4 @@ def test_mobile_document_verify(): document = mdoc.signed["documents"][0] doc = MobileDocument(**document) - #assert mdoc.verify() == True \ No newline at end of file + assert doc.verify() == True \ No newline at end of file diff --git a/pymdoccbor/tests/test_06_mso_issuer.py b/pymdoccbor/tests/test_06_mso_issuer.py index 3e926b2..b68812d 100644 --- a/pymdoccbor/tests/test_06_mso_issuer.py +++ b/pymdoccbor/tests/test_06_mso_issuer.py @@ -1,15 +1,9 @@ -import os +from pycose.keys import EC2Key from pycose.messages import CoseMessage from pymdoccbor.mso.issuer import MsoIssuer from pymdoccbor.tests.micov_data import MICOV_DATA -PKEY = { - 'KTY': 'EC2', - 'CURVE': 'P_256', - 'ALG': 'ES256', - 'D': os.urandom(32), - 'KID': b"demo-kid" -} +PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) def test_mso_issuer_fail(): try: diff --git a/pymdoccbor/tests/test_07_mso_verifier.py b/pymdoccbor/tests/test_07_mso_verifier.py index 3f2767c..b74159d 100644 --- a/pymdoccbor/tests/test_07_mso_verifier.py +++ b/pymdoccbor/tests/test_07_mso_verifier.py @@ -1,16 +1,11 @@ import os +from pycose.keys import CoseKey, EC2Key from pymdoccbor.mso.verifier import MsoVerifier from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA from pycose.messages import CoseMessage -PKEY = { - 'KTY': 'EC2', - 'CURVE': 'P_256', - 'ALG': 'ES256', - 'D': os.urandom(32), - 'KID': b"demo-kid" -} +PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) mdoc = MdocCborIssuer(PKEY) mdoc.new( From 8a1ef0247c79cc0b9187ebaa6f4be7b2be1a79c9 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Mon, 5 Feb 2024 12:21:09 +0100 Subject: [PATCH 20/21] fix: added static pkey for tests --- pymdoccbor/tests/pkey.py | 5 +++ pymdoccbor/tests/test_02_mdoc_issuer.py | 4 +-- pymdoccbor/tests/test_03_mdoc_issuer.py | 4 +-- pymdoccbor/tests/test_04_issuer_signed.py | 2 +- pymdoccbor/tests/test_05_mdoc_verifier.py | 43 +++++++++++++++++------ pymdoccbor/tests/test_06_mso_issuer.py | 2 +- pymdoccbor/tests/test_07_mso_verifier.py | 2 +- 7 files changed, 44 insertions(+), 18 deletions(-) create mode 100644 pymdoccbor/tests/pkey.py diff --git a/pymdoccbor/tests/pkey.py b/pymdoccbor/tests/pkey.py new file mode 100644 index 0000000..65a001a --- /dev/null +++ b/pymdoccbor/tests/pkey.py @@ -0,0 +1,5 @@ +from pycose.keys import EC2Key + +encoded_pkey = b'\xa6\x01\x02\x03& \x01!X \x8d%C\x91\xe8\x17A\xe1\xc2\xc1\'J\xa7\x1e\xe6J\x03\xc4\xc9\x8a\x91 hV\xcd\x10yb\x9f\xf7\xbe\x9a"X H\x8a\xc3\xd4\xc2\xea\x9bX\x9d\x9d\xf1~\x0c!\x92\xda\xfd\x02s\x0ci\xee\x190i\x88J\xddt\x14\x03\x95#X \xcd\xe1^\x92\xc8z\xd9&&\x0f\x0c\xbd\x8f4r}z\x03\x83\xe0\xf2\x8e\xcc\x04\x13M\xe1\xafXH\xcbT' + +PKEY = EC2Key.decode(encoded_pkey) \ No newline at end of file diff --git a/pymdoccbor/tests/test_02_mdoc_issuer.py b/pymdoccbor/tests/test_02_mdoc_issuer.py index 076dd9b..7ac300b 100644 --- a/pymdoccbor/tests/test_02_mdoc_issuer.py +++ b/pymdoccbor/tests/test_02_mdoc_issuer.py @@ -6,10 +6,10 @@ from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.mdoc.verifier import MdocCbor from pymdoccbor.mso.issuer import MsoIssuer -from . pid_data import PID_DATA +from pymdoccbor.tests.pid_data import PID_DATA +from pymdoccbor.tests.pkey import PKEY -PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) def test_mso_writer(): msoi = MsoIssuer( diff --git a/pymdoccbor/tests/test_03_mdoc_issuer.py b/pymdoccbor/tests/test_03_mdoc_issuer.py index 2c20e15..77dbf73 100644 --- a/pymdoccbor/tests/test_03_mdoc_issuer.py +++ b/pymdoccbor/tests/test_03_mdoc_issuer.py @@ -2,9 +2,7 @@ from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA from pymdoccbor.tests.pid_data import PID_DATA - - -PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) +from pymdoccbor.tests.pkey import PKEY mdoc = MdocCborIssuer(PKEY) diff --git a/pymdoccbor/tests/test_04_issuer_signed.py b/pymdoccbor/tests/test_04_issuer_signed.py index 24f974b..51abbdf 100644 --- a/pymdoccbor/tests/test_04_issuer_signed.py +++ b/pymdoccbor/tests/test_04_issuer_signed.py @@ -3,8 +3,8 @@ from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA from pymdoccbor.tests.test_03_mdoc_issuer import mdoc +from pymdoccbor.tests.pkey import PKEY -PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) mdoc = MdocCborIssuer(PKEY) mdoc.new( diff --git a/pymdoccbor/tests/test_05_mdoc_verifier.py b/pymdoccbor/tests/test_05_mdoc_verifier.py index 5f3eed1..4a7ff63 100644 --- a/pymdoccbor/tests/test_05_mdoc_verifier.py +++ b/pymdoccbor/tests/test_05_mdoc_verifier.py @@ -2,15 +2,7 @@ from pymdoccbor.mdoc.verifier import MobileDocument from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA - -PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) - -mdoc = MdocCborIssuer(PKEY) -mdoc.new( - data=MICOV_DATA, - devicekeyinfo=PKEY, # TODO - doctype="org.micov.medical.1" -) +from pymdoccbor.tests.pkey import PKEY def test_verifier_must_fail_document_type(): try: @@ -25,6 +17,14 @@ def test_verifier_must_fail_issuer_signed(): assert str(e) == "You must provide a signed document" def test_mobile_document(): + mdoc = MdocCborIssuer(PKEY) + mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" + ) + + document = mdoc.signed["documents"][0] doc = MobileDocument(**document) @@ -32,6 +32,14 @@ def test_mobile_document(): assert doc.issuersigned def test_mobile_document_dump(): + mdoc = MdocCborIssuer(PKEY) + mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" + ) + + document = mdoc.signed["documents"][0] doc = MobileDocument(**document) @@ -41,6 +49,14 @@ def test_mobile_document_dump(): assert len(dump) > 0 def test_mobile_document_dumps(): + mdoc = MdocCborIssuer(PKEY) + mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" + ) + + document = mdoc.signed["documents"][0] doc = MobileDocument(**document) @@ -50,7 +66,14 @@ def test_mobile_document_dumps(): assert len(dumps) > 0 def test_mobile_document_verify(): + mdoc = MdocCborIssuer(PKEY) + mdoc.new( + data=MICOV_DATA, + devicekeyinfo=PKEY, # TODO + doctype="org.micov.medical.1" + ) + document = mdoc.signed["documents"][0] doc = MobileDocument(**document) - assert doc.verify() == True \ No newline at end of file + assert doc.verify() \ No newline at end of file diff --git a/pymdoccbor/tests/test_06_mso_issuer.py b/pymdoccbor/tests/test_06_mso_issuer.py index b68812d..fbe2a7f 100644 --- a/pymdoccbor/tests/test_06_mso_issuer.py +++ b/pymdoccbor/tests/test_06_mso_issuer.py @@ -2,8 +2,8 @@ from pycose.messages import CoseMessage from pymdoccbor.mso.issuer import MsoIssuer from pymdoccbor.tests.micov_data import MICOV_DATA +from pymdoccbor.tests.pkey import PKEY -PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) def test_mso_issuer_fail(): try: diff --git a/pymdoccbor/tests/test_07_mso_verifier.py b/pymdoccbor/tests/test_07_mso_verifier.py index b74159d..d6b1aae 100644 --- a/pymdoccbor/tests/test_07_mso_verifier.py +++ b/pymdoccbor/tests/test_07_mso_verifier.py @@ -4,8 +4,8 @@ from pymdoccbor.mdoc.issuer import MdocCborIssuer from pymdoccbor.tests.micov_data import MICOV_DATA from pycose.messages import CoseMessage +from pymdoccbor.tests.pkey import PKEY -PKEY = EC2Key.generate_key(crv="P_256", optional_params={"ALG": "ES256"}) mdoc = MdocCborIssuer(PKEY) mdoc.new( From 1aedd54cbb1133f997f8fead86fc0229f054aec2 Mon Sep 17 00:00:00 2001 From: PascalDR Date: Mon, 5 Feb 2024 12:27:26 +0100 Subject: [PATCH 21/21] fix: fix workflow python's versions --- .github/workflows/python-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 9910dfa..1eb97f4 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -18,8 +18,8 @@ jobs: fail-fast: false matrix: python-version: - - '3.9' - '3.10' + - '3.11' steps: - uses: actions/checkout@v2