commit cc51ca2c2e45abd0f41f71653c4893d69a511f93
Author: Stanislav Král <stanislav.kral3@gmail.com>
Date:   Sun Apr 4 02:00:47 2021 +0200

    Re #8472 - Finished implementation of parse_cert_pem method that parses a subject out of a PEM formatted certificate
    
    Added few unit tests testing this method.

diff --git a/src/services/cryptography.py b/src/services/cryptography.py
index 450cc31..f286e71 100644
--- a/src/services/cryptography.py
+++ b/src/services/cryptography.py
@@ -2,6 +2,7 @@ import subprocess
 import re
 
 # encryption method to be used when generating private keys
+from src.model.subject import Subject
 from src.utils.temporary_file import TemporaryFile
 
 PRIVATE_KEY_ENCRYPTION_METHOD = "-aes256"
@@ -227,20 +228,41 @@ class CryptographyService:
             raise CryptographyException(OPENSSL_EXECUTABLE, args, err.decode())
 
     def parse_cert_pem(self, cert_pem):
+        """
+        Parses the given certificate in PEM format and returns the subject of the certificate
+        :param cert_pem: a certificated in a PEM format to be parsed
+        :return: a subject stored within the supplied certificate
+        """
+        # run openssl x509 to view certificate content
         args = ["x509", "-noout", "-text", "-in", "-"]
-
         result = self.__run_for_output(args, proc_input=bytes(cert_pem, encoding="utf-8")).decode()
+
+        # find the line containing the subject
         match = re.search(r"Subject:\s(.*)", result)
-        pass
-        # TODO use logger
         if match is None:
+            # TODO use logger
             print(f"Could not find subject to parse: {result}")
+            return None
         else:
-            found = re.findall(r"\s?([^=\s]+)\s?=\s?([^,\n]+)", match)
-            print(found)
-            for pair in found:
-                print(pair)
-
+            # find all attributes (key = value
+            found = re.findall(r"\s?([^c=\s]+)\s?=\s?([^,\n]+)", match.group())
+            subj = Subject()
+            for key, value in found:
+                if key == "C":
+                    subj.country = value
+                elif key == "ST":
+                    subj.state = value
+                elif key == "L":
+                    subj.locality = value
+                elif key == "O":
+                    subj.organization = value
+                elif key == "OU":
+                    subj.organization_unit = value
+                elif key == "CN":
+                    subj.common_name = value
+                elif key == "emailAddress":
+                    subj.email_address = value
+            return subj
 
 
 class CryptographyException(Exception):
diff --git a/tests/services/cryptography/parse_cert_pem_test.py b/tests/services/cryptography/parse_cert_pem_test.py
index e13af7e..bbb3ef7 100644
--- a/tests/services/cryptography/parse_cert_pem_test.py
+++ b/tests/services/cryptography/parse_cert_pem_test.py
@@ -1,3 +1,6 @@
+from src.model.subject import Subject
+
+
 def test_parse_cert_pem(service):
     cert_pem = """
 -----BEGIN CERTIFICATE-----
@@ -38,4 +41,113 @@ XXwUYr8GuSFQZb1Q4BpCayCYvTLj+7q3z72BCqAA+jMJYV/qU0EpsuFjPvzU8apg
 -----END CERTIFICATE-----
     """
 
-    # service.parse_cert_pem(cert_pem)
+    # parse a certificate supplied in a PEM format
+    subj = service.parse_cert_pem(cert_pem)
+
+    assert "CZ" == subj.country
+    assert "Pilsen Region" == subj.state
+    assert "Pilsen" == subj.locality
+    assert "Rooting Roots" == subj.organization
+    assert "Department of ROots" == subj.organization_unit
+    assert "Main Rooter" == subj.common_name
+    assert "root@root.cz" == subj.email_address
+
+
+def test_parse_cert_pen_2(service):
+    cert_pem = """
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIUIuCWtR9ae01+4iLbyoRT8I+l/EIwDQYJKoZIhvcNAQEL
+BQAwWTELMAkGA1UEBhMCQ1oxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJQkxJTlRFUl8yMB4X
+DTIxMDMyMzIxMzI1OVoXDTI0MDMyMzIxMzI1OVowWDELMAkGA1UEBhMCQVUxEzAR
+BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
+IEx0ZDERMA8GA1UEAwwITkNISUxEXzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
+ggIKAoICAQCwJDvJ9nRxsdTeCLRzWuiYgRq4rwVMraA9sII9ZJhJ+Q7wM2Qf59bx
+maMuvZwlpx1H98zbjSwwm0ft7QVzJ4bGF++JG04XcUwaaJWMgiHqwUmrm6GYjyUf
+mv1/iG2GGpUHmkCbYGqU+1uYqegHadw/WBwM8Rggo5cyujQewrRBHvGLdNqAIL33
+tVdYuubocV//xg5YwHpM0WzKx5G6Rhat72BfMjTJlpkfIZbUCVRSSphjbHqGhYVO
+d6hQ/aCHNBLw2gWxwBFLQDbc2kxKMm81x8p6vBrYBRXINcd3kVVNw6xEYViWfJ6K
+FjNPNhvoHNjKhauKKPJHd/MmG0zTUxq3sHZyOkuoq/jxwM6ugYHhHz7z23n/6KPV
+44GPZrdi7Xk3xRs3e/EOm2IoyQHfm7QVgAc0ydnVz3XDyvRmnI+Coa5X3mNXWWiC
+ikmsOU6wbOGyL8zgFL32Uc1qCMmc2039+xp/NYTs83B0rUoefjBrfLJb8y/mwEck
+1713V5TDATCI6dQWyqF83Gybuhaw4w7m3oaMXvALX7GmyjD6A7FG+AMaB4uWPeHf
+ZSzWI1yqe4ZzLn4CTnKd6G6gdqMjVwcTr1f8GCjcl6TTbyStkKDypDrZbES8e06p
+YTg38DWaY+WtmUEtfX9kQ27q26vePZN0ibU4y990367pecU3nUG0JQIDAQABo04w
+TDBKBggrBgEFBQcBAQQ+MDwwOgYIKwYBBQUHMAKGLmh0dHBzOi8vbG9jYWxob3N0
+OjUwMDAvc3RhdGljL2ludGVybWVkaWF0ZS5jcnQwDQYJKoZIhvcNAQELBQADggIB
+AG7DMCyAphSYHmSxW0CChrMV0xJ+vNvsFHPtToxykCXZ95aZUm000zPqAVSjTWt4
+/048rzDXGSlCwyt+6eALcwYHQZrVWH0pG6jRyPruhiAlbzGgbS/fjEsn5IvGl+IP
+5wNki0iRqo9dHYWxbmSSWsrLwLD4GpvipfB1rJsqRy34j4vwoBc3LjvC+VMhd0/3
+ZFQRrXLt/t6+oQYgIkBeL3mhRI+NHWMERvXM9Z6xLm4afLFyPdxmG/sTmfOSghB7
+EoqLbfNTDFRsJj6tKKosFbqmqrtEx5kL6RXNtMjp/CdwL9olnad96G4+m9X+w2K8
+uyqmVLiTXoe69JHguhiu/nrEEqn9yAlpILCDD8X2FWWt16GhUkdPII38YmZZqbCR
+dJ/iuEiC0VhxOsenWI1b18Mm06eFgjHVzjBMZpzOMBvQPhhktmHW/G0NCKpCdCQA
+6znlT0o3hQPImW3ZMGAnVfbxwCCvQ45qP6N2dZAV9Z9Fw2XQ2ZTigtmPlieJ4Vpq
+/ZkvQVA3c5Ugu+eRdQ7rvR7LPpo7CUJtlZRrs+z7EzSOCzBgtK0eXoBGlunJH9b2
+Oj4NKr8Wp/0oBfE9/x/2JXBa9N9pjd8tOU7wDD0+w90NoK/D2+rCpCYQPa/MNAVP
+gug7Na3ya2fwlerj6YM9w+i8Csf8lUFe0gww7NLkbv54
+-----END CERTIFICATE-----
+    """
+
+    # parse a certificate supplied in a PEM format
+    subj = service.parse_cert_pem(cert_pem)
+
+    assert "AU" == subj.country
+    assert "Some-State" == subj.state
+    assert "Internet Widgits Pty Ltd" == subj.organization
+    assert "NCHILD_2" == subj.common_name
+    assert None is subj.locality
+    assert None is subj.organization_unit
+    assert None is subj.email_address
+
+
+def test_parse_cert_pen_empty(service):
+    cert_pem = """
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIUPM++Jj33iag4uaOMIzED4/rMTB4wDQYJKoZIhvcNAQEL
+BQAwSTELMAkGA1UEBhMCICAxCzAJBgNVBAgMAiAgMQowCAYDVQQKDAEgMQswCQYD
+VQQDDAIgIDEUMBIGCSqGSIb3DQEJARYFIGZvbyAwHhcNMjEwNDAzMjMzMDEwWhcN
+MjEwNTAzMjMzMDEwWjBJMQswCQYDVQQGEwIgIDELMAkGA1UECAwCICAxCjAIBgNV
+BAoMASAxCzAJBgNVBAMMAiAgMRQwEgYJKoZIhvcNAQkBFgUgZm9vIDCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALI9Ksw85aFLBw2wAeRUoxMQarXkWWbw
+FyvGCb426EcdKYEiax4BYsK+VLxJpJsIo4DnSM1c0EKNJmN4w+l93CBVhHvmA+qo
+3LYShf/DgNeKZD7KJgAWwPHBnA1eOA/8kUX0YT9Z76JpJN46KFfqaY9Scb9GBU/m
+Kr/Lm2Rkg/LehMObPfNQm3XGOvcRjHON9VoB7hZW8zt2lvWTkhia9t46p/kY90eg
+3iw5JRR/MeYBiYeikjT4g5pMZDkymWUp7eahOsoR4kGYGLkpdXVN66evWzTikUKV
+QSHdzUZOiTJ7GFJ70qqh+gAEMCf/Lx8EDbDcuz7ZH40Lr6knY2+9xe8CAwEAAaNT
+MFEwHQYDVR0OBBYEFChHMZUZ2fyOrclVGjtopKn7f/mSMB8GA1UdIwQYMBaAFChH
+MZUZ2fyOrclVGjtopKn7f/mSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggEBAETfyBYSS6drAyGY1/+z7fWKV3aS1Ocd8c/7oj1seFZ8AH+b0zktTynv
+khprZhxRGRR6cHhyVmMexSWucWb7zlJZNcO9F0/FIgoqcKODtdNczTJyrC9raeuf
+8pAqhaxXcNXXUSB8vNQKHLRtRnPCB3nZE7xSl5RRmSPyPGZyyAYygxRnLjMFgJEU
+4c1FOpvRcfRS5yWviOS6dFv+cGA8hoUMXkpIW88GfwgdO6nMSQB1wUdqKoPnaIFc
+3vjtLMWkuVZFYqvp3NN6GtyI5pw1O0FzjkLZsAeuHZyIkwpKkMsnGlGW8lz1svZ+
+7AQMsDl5rA4ZVlnLXSQlq3YXVuXZlAI=
+-----END CERTIFICATE-----
+    """
+
+    # parse a certificate supplied in a PEM format
+    subj = service.parse_cert_pem(cert_pem)
+
+    # TODO improve parsing of fields within quotes
+    assert "\"  \"" == subj.country
+    assert "\"  \"" == subj.state
+    assert "\" \"" == subj.organization
+    assert "\"  \"" == subj.common_name
+    assert None is subj.locality
+    assert None is subj.organization_unit
+    assert "\" foo \"" == subj.email_address
+
+
+def test_create_and_parse_cert(service):
+    # create a private key
+    key = service.create_private_key(passphrase="foobar")
+
+    # create a certificate
+    cert = service.create_sscrt(Subject(common_name="Foo CN", email_address="foo@bar.cz"), key, key_pass="foobar")
+
+    # parse the subject
+    parsed_subj = service.parse_cert_pem(cert)
+
+    assert "Foo CN" == parsed_subj.common_name
+    assert "foo@bar.cz" == parsed_subj.email_address
