commit e39e138f1f9abaeaa0f1679894fbd80437703089
Author: Stanislav Král <stanislav.kral3@gmail.com>
Date:   Sun Apr 4 15:31:57 2021 +0200

    Re #8472 - Improved SQL connection/cursor fixtures in such way that connection to DB happens only once per test module

diff --git a/src/db/__init__.py b/src/db/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/db/init_queries.py b/src/db/init_queries.py
new file mode 100644
index 0000000..f7a5df2
--- /dev/null
+++ b/src/db/init_queries.py
@@ -0,0 +1,95 @@
+SCHEMA_SQL = """
+/* ---------------------------------------------------- */
+/*  Generated by Enterprise Architect Version 13.5 		*/
+/*  Created On : 01-dub-2021 15:16:53 				*/
+/*  DBMS       : SQLite 								*/
+/* ---------------------------------------------------- */
+
+/* Drop Tables */
+
+DROP TABLE IF EXISTS 'PrivateKeys'
+;
+
+DROP TABLE IF EXISTS 'CertificateTypes'
+;
+
+DROP TABLE IF EXISTS 'UsageTypes'
+;
+
+DROP TABLE IF EXISTS 'Certificates'
+;
+
+DROP TABLE IF EXISTS 'CertificateUsages'
+;
+
+/* Create Tables with Primary and Foreign Keys, Check and Unique Constraints */
+
+CREATE TABLE 'PrivateKeys'
+(
+	'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+	'private_key' TEXT NOT NULL,
+	'password' TEXT NULL
+)
+;
+
+CREATE TABLE 'CertificateTypes'
+(
+	'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+	'certificate_type' TEXT NOT NULL
+)
+;
+
+CREATE TABLE 'UsageTypes'
+(
+	'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+	'usage_type' TEXT NOT NULL
+)
+;
+
+CREATE TABLE 'Certificates'
+(
+	'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+	'common_name' TEXT NOT NULL,
+	'valid_from' TEXT NOT NULL,
+	'valid_to' TEXT NOT NULL,
+	'pem_data' TEXT NOT NULL,
+	'private_key_id' INTEGER NOT NULL,
+	'certificate_type_id' INTEGER NOT NULL,
+	'parent_certificate_id' INTEGER NOT NULL,
+	CONSTRAINT 'FK_Certificates' FOREIGN KEY ('parent_certificate_id') REFERENCES 'Certificates' ('id') ON DELETE No Action ON UPDATE No Action,
+	CONSTRAINT 'FK_CertificateTypes' FOREIGN KEY ('certificate_type_id') REFERENCES 'CertificateTypes' ('id') ON DELETE No Action ON UPDATE No Action,
+	CONSTRAINT 'FK_PrivateKeys' FOREIGN KEY ('private_key_id') REFERENCES 'PrivateKeys' ('id') ON DELETE No Action ON UPDATE No Action
+)
+;
+
+CREATE TABLE 'CertificateUsages'
+(
+	'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+	'certificate_id' INTEGER NOT NULL,
+	'usage_type_id' INTEGER NOT NULL,
+	CONSTRAINT 'FK_Certificates' FOREIGN KEY ('certificate_id') REFERENCES 'Certificates' ('id') ON DELETE Cascade ON UPDATE No Action,
+	CONSTRAINT 'FK_UsageTypes' FOREIGN KEY ('usage_type_id') REFERENCES 'UsageTypes' ('id') ON DELETE No Action ON UPDATE No Action
+)
+;
+
+"""
+
+DEFAULT_VALUES_SQL = """
+/* ---------------------------------------------------- */
+/*  Generated by Enterprise Architect Version 13.5 		*/
+/*  Created On : 26-bře-2021 13:33:05 				*/
+/*  DBMS       : SQLite 								*/
+/* ---------------------------------------------------- */
+
+/* Insert default values */
+
+INSERT INTO CertificateTypes(certificate_type) VALUES('ROOT_CA');
+INSERT INTO CertificateTypes(certificate_type) VALUES('INTERMEDIATE_CA');
+INSERT INTO CertificateTypes(certificate_type) VALUES('CERTIFICATE');
+
+INSERT INTO UsageTypes(usage_type) VALUES('CA');
+INSERT INTO UsageTypes(usage_type) VALUES('SSL');
+INSERT INTO UsageTypes(usage_type) VALUES('SIGNATURE');
+INSERT INTO UsageTypes(usage_type) VALUES('AUTHENTICATION');
+
+"""
\ No newline at end of file
diff --git a/tests/dao/__init__.py b/tests/dao/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/dao/certificate_repository/__init__.py b/tests/dao/certificate_repository/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/dao/certificate_repository/conftest.py b/tests/dao/certificate_repository/conftest.py
deleted file mode 100644
index 1c6c3ec..0000000
--- a/tests/dao/certificate_repository/conftest.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import pytest
-import sqlite3
-from sqlite3 import Connection, Cursor
-
-from src.dao.certificate_repository import CertificateRepository
-from src.constants import DATABASE_FILE
-
-
-@pytest.fixture
-def repository():
-    connection: Connection = sqlite3.connect("../../../" + DATABASE_FILE)
-    cursor: Cursor = connection.cursor()
-    return CertificateRepository(connection, cursor)
diff --git a/tests/dao/certificate_repository/create_certificate.py b/tests/dao/certificate_repository/create_certificate.py
deleted file mode 100644
index a2264f6..0000000
--- a/tests/dao/certificate_repository/create_certificate.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import pytest
-from src.constants import *
-
-
-def test_connection(repository):
-    sql = f"SELECT * FROM {TAB_CERTIFICATE_TYPES}"
-    repository.cursor.execute(sql)
-    selected_rows = repository.cursor.fetchall()
-
-    assert len(selected_rows) > 1
-    assert selected_rows[ROOT_CA_ID - 1][1] == "ROOT_CA"
-    assert selected_rows[INTERMEDIATE_CA_ID - 1][1] == "INTERMEDIATE_CA"
-    assert selected_rows[CERTIFICATE_ID - 1][1] == "CERTIFICATE"
diff --git a/tests/integration_tests/__init__.py b/tests/integration_tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration_tests/dao/__init__.py b/tests/integration_tests/dao/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration_tests/dao/certificate_repository/__init__.py b/tests/integration_tests/dao/certificate_repository/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration_tests/dao/certificate_repository/conftest.py b/tests/integration_tests/dao/certificate_repository/conftest.py
new file mode 100644
index 0000000..1c6c3ec
--- /dev/null
+++ b/tests/integration_tests/dao/certificate_repository/conftest.py
@@ -0,0 +1,13 @@
+import pytest
+import sqlite3
+from sqlite3 import Connection, Cursor
+
+from src.dao.certificate_repository import CertificateRepository
+from src.constants import DATABASE_FILE
+
+
+@pytest.fixture
+def repository():
+    connection: Connection = sqlite3.connect("../../../" + DATABASE_FILE)
+    cursor: Cursor = connection.cursor()
+    return CertificateRepository(connection, cursor)
diff --git a/tests/integration_tests/dao/certificate_repository/create_certificate.py b/tests/integration_tests/dao/certificate_repository/create_certificate.py
new file mode 100644
index 0000000..a2264f6
--- /dev/null
+++ b/tests/integration_tests/dao/certificate_repository/create_certificate.py
@@ -0,0 +1,13 @@
+import pytest
+from src.constants import *
+
+
+def test_connection(repository):
+    sql = f"SELECT * FROM {TAB_CERTIFICATE_TYPES}"
+    repository.cursor.execute(sql)
+    selected_rows = repository.cursor.fetchall()
+
+    assert len(selected_rows) > 1
+    assert selected_rows[ROOT_CA_ID - 1][1] == "ROOT_CA"
+    assert selected_rows[INTERMEDIATE_CA_ID - 1][1] == "INTERMEDIATE_CA"
+    assert selected_rows[CERTIFICATE_ID - 1][1] == "CERTIFICATE"
diff --git a/tests/integration_tests/services/__init__.py b/tests/integration_tests/services/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration_tests/services/certificate_key_service_test.py b/tests/integration_tests/services/certificate_key_service_test.py
new file mode 100644
index 0000000..c0fadbc
--- /dev/null
+++ b/tests/integration_tests/services/certificate_key_service_test.py
@@ -0,0 +1,15 @@
+from src.model.subject import Subject
+
+
+def test_connection(private_key_service, certificate_service):
+    private_key = private_key_service.create_new_key(passphrase="foobar")
+
+    cert = certificate_service.create_root_ca(private_key,
+                                              Subject(common_name="FooName", organization_unit="Department of Foo"))
+
+
+def test_connection_2(private_key_service, certificate_service):
+    private_key = private_key_service.create_new_key(passphrase="foobarbaz")
+
+    certificate_service.create_root_ca(private_key,
+                                       Subject(common_name="FooNameD", organization_unit="Department of Foo"))
diff --git a/tests/integration_tests/services/conftest.py b/tests/integration_tests/services/conftest.py
new file mode 100644
index 0000000..b0f6a7d
--- /dev/null
+++ b/tests/integration_tests/services/conftest.py
@@ -0,0 +1,70 @@
+import os
+import sqlite3
+from sqlite3 import Connection
+
+import pytest
+
+from src.dao.certificate_repository import CertificateRepository
+from src.dao.private_key_repository import PrivateKeyRepository
+from src.db.init_queries import SCHEMA_SQL, DEFAULT_VALUES_SQL
+from src.services.certificate_service import CertificateService
+from src.services.cryptography import CryptographyService
+from src.services.key_service import KeyService
+
+
+# scope="module" means that this fixture is run once per module
+@pytest.fixture(scope="module")
+def connection():
+    print("Creating a new SQLITE connection to the test DB")
+    test_db_file = "test.sqlite"
+    connection: Connection = sqlite3.connect(test_db_file)
+
+    # yield the created connection
+    yield connection
+
+    # after tests have finished delete the created db file
+    try:
+        print("Deleting the test DB")
+        os.unlink(test_db_file)
+    except FileNotFoundError:
+        print(f"Could not delete {test_db_file} file containing the test DB")
+        pass
+
+
+@pytest.fixture(scope="module")
+def cursor(connection):
+    cursor = connection.cursor()
+
+    # execute db initialisation script
+    cursor.executescript(SCHEMA_SQL)
+
+    # insert default values
+    cursor.executescript(DEFAULT_VALUES_SQL)
+
+    return cursor
+
+
+# scope defaults to "function" which means that the fixture is run once per test (function)
+@pytest.fixture
+def certificate_repository(connection, cursor):
+    return CertificateRepository(connection, cursor)
+
+
+@pytest.fixture
+def private_key_repository(connection, cursor):
+    return PrivateKeyRepository(connection, cursor)
+
+
+@pytest.fixture
+def cryptography_service():
+    return CryptographyService()
+
+
+@pytest.fixture
+def private_key_service(private_key_repository, cryptography_service):
+    return KeyService(cryptography_service, private_key_repository)
+
+
+@pytest.fixture
+def certificate_service(certificate_repository, cryptography_service):
+    return CertificateService(cryptography_service, certificate_repository)
diff --git a/tests/services/__init__.py b/tests/services/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/services/certificate/__init__.py b/tests/services/certificate/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/services/certificate/conftest.py b/tests/services/certificate/conftest.py
deleted file mode 100644
index 90acfb1..0000000
--- a/tests/services/certificate/conftest.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import pytest
-import sqlite3
-import os
-from sqlite3 import Connection, Cursor
-
-from src.dao.certificate_repository import CertificateRepository
-from src.dao.private_key_repository import PrivateKeyRepository
-from src.services.certificate_service import CertificateService
-from src.services.cryptography import CryptographyService
-from src.services.key_service import KeyService
-
-
-@pytest.fixture
-def connection():
-    try:
-        os.remove("../../../test.sqlite")
-    except FileNotFoundError:
-        pass
-    connection: Connection = sqlite3.connect("../../../" + "test.sqlite")
-    return connection
-
-
-@pytest.fixture
-def cursor(connection):
-    cursor = connection.cursor()
-
-    # execute db initialisation script
-    with open('../../../SQLite_database.sql', 'r') as sql_file:
-        sql_script = sql_file.read()
-        cursor.executescript(sql_script)
-
-    # insert default values
-    with open('../../../SQLite_default_values.sql', 'r') as sql_file:
-        sql_script = sql_file.read()
-        cursor.executescript(sql_script)
-
-    return cursor
-
-
-@pytest.fixture
-def certificate_repository(connection, cursor):
-    return CertificateRepository(connection, cursor)
-
-
-@pytest.fixture
-def private_key_repository(connection, cursor):
-    return PrivateKeyRepository(connection, cursor)
-
-
-@pytest.fixture
-def cryptography_service():
-    return CryptographyService()
-
-
-@pytest.fixture
-def private_key_service(private_key_repository, cryptography_service):
-    return KeyService(cryptography_service, private_key_repository)
-
-
-@pytest.fixture
-def certificate_service(certificate_repository, cryptography_service):
-    return CertificateService(cryptography_service, certificate_repository)
diff --git a/tests/services/certificate/integration_test.py b/tests/services/certificate/integration_test.py
deleted file mode 100644
index a097b44..0000000
--- a/tests/services/certificate/integration_test.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from src.model.subject import Subject
-
-
-def test_connection(private_key_service, certificate_service):
-    private_key = private_key_service.create_new_key(passphrase="foobar")
-
-    certificate_service.create_root_ca(private_key,
-                                       Subject(common_name="FooName", organization_unit="Department of Foo"))
diff --git a/tests/services/cryptography/__init__.py b/tests/services/cryptography/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/services/cryptography/conftest.py b/tests/services/cryptography/conftest.py
deleted file mode 100644
index 365c744..0000000
--- a/tests/services/cryptography/conftest.py
+++ /dev/null
@@ -1,9 +0,0 @@
-import pytest
-
-from src.services.cryptography import CryptographyService
-
-
-@pytest.fixture
-def service():
-    # provide a CryptographyService fixture
-    return CryptographyService()
diff --git a/tests/services/cryptography/create_crt_test.py b/tests/services/cryptography/create_crt_test.py
deleted file mode 100644
index 02906eb..0000000
--- a/tests/services/cryptography/create_crt_test.py
+++ /dev/null
@@ -1,98 +0,0 @@
-import subprocess
-
-import pytest
-
-from src.model.subject import Subject
-from src.services.cryptography import CryptographyException
-
-
-def export_crt(crt):
-    return subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
-                                   input=bytes(crt, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
-
-
-def test_sign_cst(service):
-    # create root CA
-    root_key = service.create_private_key()
-    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key)
-
-    # create a private key to be used to make a CSR for the intermediate CA
-    inter_key = service.create_private_key()
-
-    # create a CA using the root CA
-    inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key)
-
-    inter_ca_printed = export_crt(inter_ca)
-
-    # assert fields
-    assert "Issuer: CN = foo" in inter_ca_printed
-    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
-
-
-def test_sign_crt_passphrase(service):
-    # create root CA and encrypt the private key of the root CA
-    root_key_passphrase = "barbaz"
-    root_key = service.create_private_key(passphrase=root_key_passphrase)
-    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
-
-    # create a private key to be used to make a CSR for the intermediate CA
-    inter_key_passphrase = "foobazbar"
-    inter_key = service.create_private_key(passphrase=inter_key_passphrase)
-
-    # create a CA using the root CA
-    inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key,
-                                  subject_key_pass=inter_key_passphrase, issuer_key_pass=root_key_passphrase)
-
-    inter_ca_printed = export_crt(inter_ca)
-
-    # assert fields
-    assert "Issuer: CN = foo" in inter_ca_printed
-    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
-
-    # some basic incorrect passphrase combinations
-    passphrases = [
-        (inter_key, None),
-        (inter_key, "foofoobarbar"),
-        (None, root_key),
-        ("foofoobarbar", root_key),
-        ("foofoobarbar", "foofoobarbar"),
-        (None, None)
-    ]
-
-    for (key_pass, issuer_key_pass) in passphrases:
-        # try to create it using a wrong issuer passphrase
-        with pytest.raises(CryptographyException) as e:
-            inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key,
-                                          subject_key_pass=key_pass, issuer_key_pass=issuer_key_pass)
-        assert "bad decrypt" in e.value.message
-
-
-def test_sign_crt_extensions(service):
-    # create root CA and encrypt the private key of the root CA
-    root_key_passphrase = "barbaz"
-    root_key = service.create_private_key(passphrase=root_key_passphrase)
-    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
-
-    # create a private key to be used to make a CSR for the intermediate CA
-    inter_key_passphrase = "foofoo"
-    inter_key = service.create_private_key()
-
-    # create a CA using the root CA
-    inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key,
-                                  subject_key_pass=inter_key_passphrase, issuer_key_pass=root_key_passphrase,
-                                  extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz/cert\nbasicConstraints=critical,CA:TRUE")
-
-    inter_ca_printed = export_crt(inter_ca)
-
-    # assert fields
-    assert "Issuer: CN = foo" in inter_ca_printed
-    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
-
-    # assert extensions
-    expected_extensions = """        X509v3 extensions:
-            Authority Information Access: 
-                CA Issuers - URI:bar.cz/baz/cert
-
-            X509v3 Basic Constraints: critical
-                CA:TRUE"""
-    assert expected_extensions in inter_ca_printed
diff --git a/tests/services/cryptography/create_csr_test.py b/tests/services/cryptography/create_csr_test.py
deleted file mode 100644
index 135bb3e..0000000
--- a/tests/services/cryptography/create_csr_test.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import subprocess
-
-from src.model.subject import Subject
-
-
-def get_csr_pem(csr):
-    return subprocess.check_output(["openssl", "req", "-noout", "-text", "-verify", "-in", "-"],
-                                   input=bytes(csr, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
-
-
-def test_make_csr(service):
-    private_key = service.create_private_key()
-
-    subject = Subject(common_name="foo", country="CZ")
-    csr = service._CryptographyService__create_csr(subject, private_key)
-
-    assert "Subject: CN = foo, C = CZ" in get_csr_pem(csr)
-
-
-def test_make_csr_pkey_passphrase(service):
-    private_key = service.create_private_key(passphrase="foobar")
-
-    subject = Subject(common_name="foo", country="CZ", organization_unit="Mysterious Unit")
-    csr = service._CryptographyService__create_csr(subject, private_key, key_pass="foobar")
-
-    assert "Subject: CN = foo, C = CZ, OU = Mysterious Unit" in get_csr_pem(csr)
diff --git a/tests/services/cryptography/parse_cert_pem_test.py b/tests/services/cryptography/parse_cert_pem_test.py
deleted file mode 100644
index eb5e2bf..0000000
--- a/tests/services/cryptography/parse_cert_pem_test.py
+++ /dev/null
@@ -1,195 +0,0 @@
-from src.model.subject import Subject
-
-
-def test_parse_cert_pem(service):
-    cert_pem = """
------BEGIN CERTIFICATE-----
-
-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
------END CERTIFICATE-----
-    """
-
-    # parse a certificate supplied in a PEM format
-    subj, n_before, n_after = service.parse_cert_pem(cert_pem)
-
-    assert 3 == n_before.tm_mon
-    assert 21 == n_before.tm_mday
-    assert 10 == n_before.tm_hour
-    assert 1 == n_before.tm_min
-    assert 52 == n_before.tm_sec
-    assert 2021 == n_before.tm_year
-
-    assert 3 == n_after.tm_mon
-    assert 21 == n_after.tm_mday
-    assert 10 == n_after.tm_hour
-    assert 1 == n_after.tm_min
-    assert 52 == n_after.tm_sec
-    assert 2026 == n_after.tm_year
-
-    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, n_before, n_after = service.parse_cert_pem(cert_pem)
-
-    assert 3 == n_before.tm_mon
-    assert 23 == n_before.tm_mday
-    assert 21 == n_before.tm_hour
-    assert 32 == n_before.tm_min
-    assert 59 == n_before.tm_sec
-    assert 2021 == n_before.tm_year
-
-    assert 3 == n_after.tm_mon
-    assert 23 == n_after.tm_mday
-    assert 21 == n_after.tm_hour
-    assert 32 == n_after.tm_min
-    assert 59 == n_after.tm_sec
-    assert 2024 == n_after.tm_year
-
-    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, n_before, n_after = service.parse_cert_pem(cert_pem)
-
-    assert 4 == n_before.tm_mon
-    assert 3 == n_before.tm_mday
-    assert 23 == n_before.tm_hour
-    assert 30 == n_before.tm_min
-    assert 10 == n_before.tm_sec
-    assert 2021 == n_before.tm_year
-
-    assert 5 == n_after.tm_mon
-    assert 3 == n_after.tm_mday
-    assert 23 == n_after.tm_hour
-    assert 30 == n_after.tm_min
-    assert 10 == n_after.tm_sec
-    assert 2021 == n_after.tm_year
-
-    # 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, n_before, n_after = service.parse_cert_pem(cert)
-
-    assert "Foo CN" == parsed_subj.common_name
-    assert "foo@bar.cz" == parsed_subj.email_address
diff --git a/tests/services/cryptography/private_keys_test.py b/tests/services/cryptography/private_keys_test.py
deleted file mode 100644
index b1f53bb..0000000
--- a/tests/services/cryptography/private_keys_test.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import subprocess
-
-import pytest
-
-
-def test_private_key(service):
-    private_key = service.create_private_key()
-
-    # verify the private key
-    subprocess.check_output(["openssl", "rsa", "-in", "-", "-check"], input=bytes(private_key, encoding="utf-8"),
-                            stderr=subprocess.STDOUT)
-
-
-def test_encrypted_private_key(service):
-    private_key = service.create_private_key(passphrase="foobar")
-
-    # verify the private key providing a correct passphrase
-    subprocess.check_output(["openssl", "rsa", "-in", "-", "-passin", "pass:foobar", "-check"],
-                            input=bytes(private_key, encoding="utf-8"), stderr=subprocess.STDOUT)
-
-
-def test_encrypted_private_key_incorrect_pass(service):
-    private_key = service.create_private_key(passphrase="foobar")
-
-    # incorrect passphrase provided
-    with pytest.raises(subprocess.CalledProcessError):
-        subprocess.check_output(["openssl", "rsa", "-in", "-", "-passin", "pass:bazbaz", "-check"],
-                                input=bytes(private_key, encoding="utf-8"), stderr=subprocess.STDOUT)
diff --git a/tests/services/cryptography/run_for_output_test.py b/tests/services/cryptography/run_for_output_test.py
deleted file mode 100644
index 3957791..0000000
--- a/tests/services/cryptography/run_for_output_test.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import pytest
-
-from src.services.cryptography import CryptographyException
-
-
-def test_simple_exec(service):
-    out = service._CryptographyService__run_for_output(["version"])
-    assert "OpenSSL" in out.decode()
-
-
-def test_simple_exec_without_parameters(service):
-    out = service._CryptographyService__run_for_output()
-    assert "OpenSSL>" in out.decode()
-
-
-def test_nonexistent_executable(service):
-    with pytest.raises(CryptographyException) as e:
-        service._CryptographyService__run_for_output(executable="nonexistent_executable#")
-    assert """"nonexistent_executable#" not found in the current PATH.""" in e.value.message
-
-
-def test_exception_str(service):
-    with pytest.raises(CryptographyException) as e:
-        service._CryptographyService__run_for_output(executable="nonexistent_executable")
-    assert """EXECUTABLE: nonexistent_executable
-        ARGS: ('nonexistent_executable',)
-        MESSAGE: "nonexistent_executable" not found in the current PATH.""" in e.value.__str__()
diff --git a/tests/services/cryptography/self_signed_cert_test.py b/tests/services/cryptography/self_signed_cert_test.py
deleted file mode 100644
index 83a7b46..0000000
--- a/tests/services/cryptography/self_signed_cert_test.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import subprocess
-
-import pytest
-
-from src.model.subject import Subject
-from src.services.cryptography import CryptographyException
-
-
-def test_create_sscrt(service):
-    # create a self signed certificate using configuration and extensions
-    private_key = service.create_private_key(passphrase="foobar")
-
-    # distinguished_name is always required
-    config = """
-    # Simple Root CA
-
-    [ req ]
-    distinguished_name      = ca_dn                 # DN section
-
-    [ ca_dn ]
-
-    [ root_ca_ext ]
-    keyUsage                = critical,keyCertSign,cRLSign
-    basicConstraints        = critical,CA:true
-    subjectKeyIdentifier    = hash
-    authorityKeyIdentifier  = keyid:always
-    """
-
-    cert = service.create_sscrt(Subject(common_name="Topnax",
-                                        country="CZ",
-                                        locality="My Locality",
-                                        state="My state",
-                                        organization="Mysterious Org.",
-                                        organization_unit="Department of Mysteries",
-                                        email_address="mysterious@box.cz"), private_key, config=config,
-                                extensions="root_ca_ext", key_pass="foobar")
-
-    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
-                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
-
-    assert "Certificate Sign, CRL Sign" in cert_printed
-    assert "X509v3 Key Usage: critical" in cert_printed
-    assert "CA:TRUE" in cert_printed
-
-    assert "Issuer: CN = Topnax, C = CZ, L = My Locality, ST = My state, O = Mysterious Org., OU = Department of Mysteries, emailAddress = mysterious@box.cz" in cert_printed
-    assert "Subject: CN = Topnax, C = CZ, L = My Locality, ST = My state, O = Mysterious Org., OU = Department of Mysteries, emailAddress = mysterious@box.cz" in cert_printed
-
-
-def test_create_sscrt_config_without_extensions(service):
-    # create a self signed certificate without specifying extensions
-    private_key = service.create_private_key()
-
-    config = """
-    # Simple Root CA
-
-    [ req ]
-    distinguished_name      = ca_dn                 # DN section
-
-    [ ca_dn ]
-
-    """
-
-    cert = service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key, config=config)
-
-    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
-                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
-
-    # TODO pass something in the configuration that can be asserted
-    assert "Issuer: CN = Topnax, C = CZ" in cert_printed
-    assert "Subject: CN = Topnax, C = CZ" in cert_printed
-
-
-def test_create_sscrt_plain(service):
-    # create a self signed certificate without configuration
-    private_key = service.create_private_key()
-
-    cert = service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key)
-
-    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
-                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
-
-    assert "Issuer: CN = Topnax, C = CZ" in cert_printed
-    assert "Subject: CN = Topnax, C = CZ" in cert_printed
-
-
-def test_create_sscrt_passphrase(service):
-    # create a self signed certificate with a PK that is protected by a passphrase
-    private_key = service.create_private_key(passphrase="foobar")
-
-    cert = service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key, key_pass="foobar")
-
-    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
-                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
-
-    assert "Issuer: CN = Topnax, C = CZ" in cert_printed
-    assert "Subject: CN = Topnax, C = CZ" in cert_printed
-
-
-def test_create_sscrt_incorrect_passphrase(service):
-    # make an attempt to create a self signed certificate using a private key with specifying wrong key passphrase or
-    # no passphrase at all
-    private_key = service.create_private_key(passphrase="foobar")
-
-    # incorrect passphrase provided when using a protected private key
-    with pytest.raises(CryptographyException) as e:
-        service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key, key_pass="bazfoo")
-    assert "bad decrypt" in e.value.message
-
-    # no passphrase provided when using a protected private key
-    with pytest.raises(CryptographyException) as e:
-        service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key)
-    assert "bad decrypt" in e.value.message
diff --git a/tests/services/cryptography/sign_csr_test.py b/tests/services/cryptography/sign_csr_test.py
deleted file mode 100644
index 64c9d73..0000000
--- a/tests/services/cryptography/sign_csr_test.py
+++ /dev/null
@@ -1,94 +0,0 @@
-import subprocess
-
-import pytest
-
-from src.model.subject import Subject
-from src.services.cryptography import CryptographyException
-
-
-def export_crt(csr):
-    return subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
-                                   input=bytes(csr, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
-
-
-def test_sign_csr(service):
-    # create root CA
-    root_key = service.create_private_key()
-    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key)
-
-    # create a private key to be used to make a CSR for the intermediate CA
-    inter_key = service.create_private_key()
-    csr = service._CryptographyService__create_csr(Subject(common_name="bar", country="CZ"), inter_key)
-
-    # sign the created CSR with root CA
-    inter_ca = service._CryptographyService__sign_csr(csr, root_ca, root_key)
-
-    inter_ca_printed = export_crt(inter_ca)
-
-    # assert fields
-    assert "Issuer: CN = foo" in inter_ca_printed
-    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
-
-
-def test_sign_csr_passphrase(service):
-    # create root CA and encrypt the private key of the root CA
-    root_key_passphrase = "barbaz"
-    root_key = service.create_private_key(passphrase=root_key_passphrase)
-    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
-
-    # create a private key to be used to make a CSR for the intermediate CA
-    inter_key = service.create_private_key()
-    csr = service._CryptographyService__create_csr(Subject(common_name="bar", country="CZ"), inter_key)
-
-    # sign the created CSR with root CA and specify root key passphrase
-    inter_ca = service._CryptographyService__sign_csr(csr, root_ca, root_key, issuer_key_pass=root_key_passphrase)
-
-    inter_ca_printed = export_crt(inter_ca)
-
-    # assert fields
-    assert "Issuer: CN = foo" in inter_ca_printed
-    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
-
-    # try to sign it using a wrong passphrase
-    with pytest.raises(CryptographyException) as e:
-        service._CryptographyService__sign_csr(csr, root_ca, root_key,
-                                               extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz.cert",
-                                               issuer_key_pass="bazbaz")
-    assert "bad decrypt" in e.value.message
-
-    # try to sign it without specifying a passphrase
-    with pytest.raises(CryptographyException) as e:
-        service._CryptographyService__sign_csr(csr, root_ca, root_key,
-                                               extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz.cert")
-    assert "bad decrypt" in e.value.message
-
-
-def test_sign_csr_extensions(service):
-    # create root CA and encrypt the private key of the root CA
-    root_key_passphrase = "barbaz"
-    root_key = service.create_private_key(passphrase=root_key_passphrase)
-    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
-
-    # create a private key to be used to make a CSR for the intermediate CA
-    inter_key = service.create_private_key()
-    csr = service._CryptographyService__create_csr(Subject(common_name="bar", country="CZ"), inter_key)
-
-    # sign the created CSR with root CA and specify root key passphrase and specify extensions (AIA and CA)
-    inter_ca = service._CryptographyService__sign_csr(csr, root_ca, root_key,
-                                                      extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz/cert\nbasicConstraints=critical,CA:TRUE",
-                                                      issuer_key_pass=root_key_passphrase)
-
-    inter_ca_printed = export_crt(inter_ca)
-
-    # assert fields
-    assert "Issuer: CN = foo" in inter_ca_printed
-    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
-
-    # assert extensions
-    expected_extensions = """        X509v3 extensions:
-            Authority Information Access: 
-                CA Issuers - URI:bar.cz/baz/cert
-
-            X509v3 Basic Constraints: critical
-                CA:TRUE"""
-    assert expected_extensions in inter_ca_printed
diff --git a/tests/services/cryptography/verify_ca_test.py b/tests/services/cryptography/verify_ca_test.py
deleted file mode 100644
index d3f68fe..0000000
--- a/tests/services/cryptography/verify_ca_test.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import pytest
-
-from src.model.subject import Subject
-from src.services.cryptography import CryptographyException
-
-
-def test_verify_valid_ca(service):
-    # verify validation of valid certificates
-    private_key = service.create_private_key()
-    root_cert = service.create_sscrt(Subject(common_name="foo"), private_key)
-    child_cert = service.create_crt(Subject(common_name="Expired Foo"), private_key, root_cert, private_key, days=1)
-
-    assert service.verify_cert(root_cert)
-    assert service.verify_cert(child_cert)
-
-
-def test_verify_invalid_ca(service):
-    # test whether expired certificate will fail to get verified
-    private_key = service.create_private_key()
-    root_cert = service.create_sscrt(Subject(common_name="foo"), private_key)
-
-    expired_cert = service.create_crt(Subject(common_name="Expired Foo"), private_key, root_cert, private_key, days=0)
-
-    assert not service.verify_cert(expired_cert)
-
-
-def test_verify_invalid_cert_format(service):
-    # verify that certificate in invalid format raises <CryptographyException>
-
-    with pytest.raises(CryptographyException):
-        service.verify_cert("invalid cert")
diff --git a/tests/unit_tests/__init__.py b/tests/unit_tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/unit_tests/services/__init__.py b/tests/unit_tests/services/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/unit_tests/services/cryptography/__init__.py b/tests/unit_tests/services/cryptography/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/unit_tests/services/cryptography/conftest.py b/tests/unit_tests/services/cryptography/conftest.py
new file mode 100644
index 0000000..365c744
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/conftest.py
@@ -0,0 +1,9 @@
+import pytest
+
+from src.services.cryptography import CryptographyService
+
+
+@pytest.fixture
+def service():
+    # provide a CryptographyService fixture
+    return CryptographyService()
diff --git a/tests/unit_tests/services/cryptography/create_crt_test.py b/tests/unit_tests/services/cryptography/create_crt_test.py
new file mode 100644
index 0000000..02906eb
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/create_crt_test.py
@@ -0,0 +1,98 @@
+import subprocess
+
+import pytest
+
+from src.model.subject import Subject
+from src.services.cryptography import CryptographyException
+
+
+def export_crt(crt):
+    return subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
+                                   input=bytes(crt, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
+
+
+def test_sign_cst(service):
+    # create root CA
+    root_key = service.create_private_key()
+    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key)
+
+    # create a private key to be used to make a CSR for the intermediate CA
+    inter_key = service.create_private_key()
+
+    # create a CA using the root CA
+    inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key)
+
+    inter_ca_printed = export_crt(inter_ca)
+
+    # assert fields
+    assert "Issuer: CN = foo" in inter_ca_printed
+    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
+
+
+def test_sign_crt_passphrase(service):
+    # create root CA and encrypt the private key of the root CA
+    root_key_passphrase = "barbaz"
+    root_key = service.create_private_key(passphrase=root_key_passphrase)
+    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
+
+    # create a private key to be used to make a CSR for the intermediate CA
+    inter_key_passphrase = "foobazbar"
+    inter_key = service.create_private_key(passphrase=inter_key_passphrase)
+
+    # create a CA using the root CA
+    inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key,
+                                  subject_key_pass=inter_key_passphrase, issuer_key_pass=root_key_passphrase)
+
+    inter_ca_printed = export_crt(inter_ca)
+
+    # assert fields
+    assert "Issuer: CN = foo" in inter_ca_printed
+    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
+
+    # some basic incorrect passphrase combinations
+    passphrases = [
+        (inter_key, None),
+        (inter_key, "foofoobarbar"),
+        (None, root_key),
+        ("foofoobarbar", root_key),
+        ("foofoobarbar", "foofoobarbar"),
+        (None, None)
+    ]
+
+    for (key_pass, issuer_key_pass) in passphrases:
+        # try to create it using a wrong issuer passphrase
+        with pytest.raises(CryptographyException) as e:
+            inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key,
+                                          subject_key_pass=key_pass, issuer_key_pass=issuer_key_pass)
+        assert "bad decrypt" in e.value.message
+
+
+def test_sign_crt_extensions(service):
+    # create root CA and encrypt the private key of the root CA
+    root_key_passphrase = "barbaz"
+    root_key = service.create_private_key(passphrase=root_key_passphrase)
+    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
+
+    # create a private key to be used to make a CSR for the intermediate CA
+    inter_key_passphrase = "foofoo"
+    inter_key = service.create_private_key()
+
+    # create a CA using the root CA
+    inter_ca = service.create_crt(Subject(common_name="bar", country="CZ"), inter_key, root_ca, root_key,
+                                  subject_key_pass=inter_key_passphrase, issuer_key_pass=root_key_passphrase,
+                                  extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz/cert\nbasicConstraints=critical,CA:TRUE")
+
+    inter_ca_printed = export_crt(inter_ca)
+
+    # assert fields
+    assert "Issuer: CN = foo" in inter_ca_printed
+    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
+
+    # assert extensions
+    expected_extensions = """        X509v3 extensions:
+            Authority Information Access: 
+                CA Issuers - URI:bar.cz/baz/cert
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE"""
+    assert expected_extensions in inter_ca_printed
diff --git a/tests/unit_tests/services/cryptography/create_csr_test.py b/tests/unit_tests/services/cryptography/create_csr_test.py
new file mode 100644
index 0000000..135bb3e
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/create_csr_test.py
@@ -0,0 +1,26 @@
+import subprocess
+
+from src.model.subject import Subject
+
+
+def get_csr_pem(csr):
+    return subprocess.check_output(["openssl", "req", "-noout", "-text", "-verify", "-in", "-"],
+                                   input=bytes(csr, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
+
+
+def test_make_csr(service):
+    private_key = service.create_private_key()
+
+    subject = Subject(common_name="foo", country="CZ")
+    csr = service._CryptographyService__create_csr(subject, private_key)
+
+    assert "Subject: CN = foo, C = CZ" in get_csr_pem(csr)
+
+
+def test_make_csr_pkey_passphrase(service):
+    private_key = service.create_private_key(passphrase="foobar")
+
+    subject = Subject(common_name="foo", country="CZ", organization_unit="Mysterious Unit")
+    csr = service._CryptographyService__create_csr(subject, private_key, key_pass="foobar")
+
+    assert "Subject: CN = foo, C = CZ, OU = Mysterious Unit" in get_csr_pem(csr)
diff --git a/tests/unit_tests/services/cryptography/parse_cert_pem_test.py b/tests/unit_tests/services/cryptography/parse_cert_pem_test.py
new file mode 100644
index 0000000..eb5e2bf
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/parse_cert_pem_test.py
@@ -0,0 +1,195 @@
+from src.model.subject import Subject
+
+
+def test_parse_cert_pem(service):
+    cert_pem = """
+-----BEGIN CERTIFICATE-----
+
+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
+-----END CERTIFICATE-----
+    """
+
+    # parse a certificate supplied in a PEM format
+    subj, n_before, n_after = service.parse_cert_pem(cert_pem)
+
+    assert 3 == n_before.tm_mon
+    assert 21 == n_before.tm_mday
+    assert 10 == n_before.tm_hour
+    assert 1 == n_before.tm_min
+    assert 52 == n_before.tm_sec
+    assert 2021 == n_before.tm_year
+
+    assert 3 == n_after.tm_mon
+    assert 21 == n_after.tm_mday
+    assert 10 == n_after.tm_hour
+    assert 1 == n_after.tm_min
+    assert 52 == n_after.tm_sec
+    assert 2026 == n_after.tm_year
+
+    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, n_before, n_after = service.parse_cert_pem(cert_pem)
+
+    assert 3 == n_before.tm_mon
+    assert 23 == n_before.tm_mday
+    assert 21 == n_before.tm_hour
+    assert 32 == n_before.tm_min
+    assert 59 == n_before.tm_sec
+    assert 2021 == n_before.tm_year
+
+    assert 3 == n_after.tm_mon
+    assert 23 == n_after.tm_mday
+    assert 21 == n_after.tm_hour
+    assert 32 == n_after.tm_min
+    assert 59 == n_after.tm_sec
+    assert 2024 == n_after.tm_year
+
+    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, n_before, n_after = service.parse_cert_pem(cert_pem)
+
+    assert 4 == n_before.tm_mon
+    assert 3 == n_before.tm_mday
+    assert 23 == n_before.tm_hour
+    assert 30 == n_before.tm_min
+    assert 10 == n_before.tm_sec
+    assert 2021 == n_before.tm_year
+
+    assert 5 == n_after.tm_mon
+    assert 3 == n_after.tm_mday
+    assert 23 == n_after.tm_hour
+    assert 30 == n_after.tm_min
+    assert 10 == n_after.tm_sec
+    assert 2021 == n_after.tm_year
+
+    # 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, n_before, n_after = service.parse_cert_pem(cert)
+
+    assert "Foo CN" == parsed_subj.common_name
+    assert "foo@bar.cz" == parsed_subj.email_address
diff --git a/tests/unit_tests/services/cryptography/private_keys_test.py b/tests/unit_tests/services/cryptography/private_keys_test.py
new file mode 100644
index 0000000..b1f53bb
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/private_keys_test.py
@@ -0,0 +1,28 @@
+import subprocess
+
+import pytest
+
+
+def test_private_key(service):
+    private_key = service.create_private_key()
+
+    # verify the private key
+    subprocess.check_output(["openssl", "rsa", "-in", "-", "-check"], input=bytes(private_key, encoding="utf-8"),
+                            stderr=subprocess.STDOUT)
+
+
+def test_encrypted_private_key(service):
+    private_key = service.create_private_key(passphrase="foobar")
+
+    # verify the private key providing a correct passphrase
+    subprocess.check_output(["openssl", "rsa", "-in", "-", "-passin", "pass:foobar", "-check"],
+                            input=bytes(private_key, encoding="utf-8"), stderr=subprocess.STDOUT)
+
+
+def test_encrypted_private_key_incorrect_pass(service):
+    private_key = service.create_private_key(passphrase="foobar")
+
+    # incorrect passphrase provided
+    with pytest.raises(subprocess.CalledProcessError):
+        subprocess.check_output(["openssl", "rsa", "-in", "-", "-passin", "pass:bazbaz", "-check"],
+                                input=bytes(private_key, encoding="utf-8"), stderr=subprocess.STDOUT)
diff --git a/tests/unit_tests/services/cryptography/run_for_output_test.py b/tests/unit_tests/services/cryptography/run_for_output_test.py
new file mode 100644
index 0000000..3957791
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/run_for_output_test.py
@@ -0,0 +1,27 @@
+import pytest
+
+from src.services.cryptography import CryptographyException
+
+
+def test_simple_exec(service):
+    out = service._CryptographyService__run_for_output(["version"])
+    assert "OpenSSL" in out.decode()
+
+
+def test_simple_exec_without_parameters(service):
+    out = service._CryptographyService__run_for_output()
+    assert "OpenSSL>" in out.decode()
+
+
+def test_nonexistent_executable(service):
+    with pytest.raises(CryptographyException) as e:
+        service._CryptographyService__run_for_output(executable="nonexistent_executable#")
+    assert """"nonexistent_executable#" not found in the current PATH.""" in e.value.message
+
+
+def test_exception_str(service):
+    with pytest.raises(CryptographyException) as e:
+        service._CryptographyService__run_for_output(executable="nonexistent_executable")
+    assert """EXECUTABLE: nonexistent_executable
+        ARGS: ('nonexistent_executable',)
+        MESSAGE: "nonexistent_executable" not found in the current PATH.""" in e.value.__str__()
diff --git a/tests/unit_tests/services/cryptography/self_signed_cert_test.py b/tests/unit_tests/services/cryptography/self_signed_cert_test.py
new file mode 100644
index 0000000..83a7b46
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/self_signed_cert_test.py
@@ -0,0 +1,112 @@
+import subprocess
+
+import pytest
+
+from src.model.subject import Subject
+from src.services.cryptography import CryptographyException
+
+
+def test_create_sscrt(service):
+    # create a self signed certificate using configuration and extensions
+    private_key = service.create_private_key(passphrase="foobar")
+
+    # distinguished_name is always required
+    config = """
+    # Simple Root CA
+
+    [ req ]
+    distinguished_name      = ca_dn                 # DN section
+
+    [ ca_dn ]
+
+    [ root_ca_ext ]
+    keyUsage                = critical,keyCertSign,cRLSign
+    basicConstraints        = critical,CA:true
+    subjectKeyIdentifier    = hash
+    authorityKeyIdentifier  = keyid:always
+    """
+
+    cert = service.create_sscrt(Subject(common_name="Topnax",
+                                        country="CZ",
+                                        locality="My Locality",
+                                        state="My state",
+                                        organization="Mysterious Org.",
+                                        organization_unit="Department of Mysteries",
+                                        email_address="mysterious@box.cz"), private_key, config=config,
+                                extensions="root_ca_ext", key_pass="foobar")
+
+    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
+                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
+
+    assert "Certificate Sign, CRL Sign" in cert_printed
+    assert "X509v3 Key Usage: critical" in cert_printed
+    assert "CA:TRUE" in cert_printed
+
+    assert "Issuer: CN = Topnax, C = CZ, L = My Locality, ST = My state, O = Mysterious Org., OU = Department of Mysteries, emailAddress = mysterious@box.cz" in cert_printed
+    assert "Subject: CN = Topnax, C = CZ, L = My Locality, ST = My state, O = Mysterious Org., OU = Department of Mysteries, emailAddress = mysterious@box.cz" in cert_printed
+
+
+def test_create_sscrt_config_without_extensions(service):
+    # create a self signed certificate without specifying extensions
+    private_key = service.create_private_key()
+
+    config = """
+    # Simple Root CA
+
+    [ req ]
+    distinguished_name      = ca_dn                 # DN section
+
+    [ ca_dn ]
+
+    """
+
+    cert = service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key, config=config)
+
+    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
+                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
+
+    # TODO pass something in the configuration that can be asserted
+    assert "Issuer: CN = Topnax, C = CZ" in cert_printed
+    assert "Subject: CN = Topnax, C = CZ" in cert_printed
+
+
+def test_create_sscrt_plain(service):
+    # create a self signed certificate without configuration
+    private_key = service.create_private_key()
+
+    cert = service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key)
+
+    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
+                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
+
+    assert "Issuer: CN = Topnax, C = CZ" in cert_printed
+    assert "Subject: CN = Topnax, C = CZ" in cert_printed
+
+
+def test_create_sscrt_passphrase(service):
+    # create a self signed certificate with a PK that is protected by a passphrase
+    private_key = service.create_private_key(passphrase="foobar")
+
+    cert = service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key, key_pass="foobar")
+
+    cert_printed = subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
+                                           input=bytes(cert, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
+
+    assert "Issuer: CN = Topnax, C = CZ" in cert_printed
+    assert "Subject: CN = Topnax, C = CZ" in cert_printed
+
+
+def test_create_sscrt_incorrect_passphrase(service):
+    # make an attempt to create a self signed certificate using a private key with specifying wrong key passphrase or
+    # no passphrase at all
+    private_key = service.create_private_key(passphrase="foobar")
+
+    # incorrect passphrase provided when using a protected private key
+    with pytest.raises(CryptographyException) as e:
+        service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key, key_pass="bazfoo")
+    assert "bad decrypt" in e.value.message
+
+    # no passphrase provided when using a protected private key
+    with pytest.raises(CryptographyException) as e:
+        service.create_sscrt(Subject(common_name="Topnax", country="CZ"), private_key)
+    assert "bad decrypt" in e.value.message
diff --git a/tests/unit_tests/services/cryptography/sign_csr_test.py b/tests/unit_tests/services/cryptography/sign_csr_test.py
new file mode 100644
index 0000000..64c9d73
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/sign_csr_test.py
@@ -0,0 +1,94 @@
+import subprocess
+
+import pytest
+
+from src.model.subject import Subject
+from src.services.cryptography import CryptographyException
+
+
+def export_crt(csr):
+    return subprocess.check_output(["openssl", "x509", "-noout", "-text", "-in", "-"],
+                                   input=bytes(csr, encoding="utf-8"), stderr=subprocess.STDOUT).decode()
+
+
+def test_sign_csr(service):
+    # create root CA
+    root_key = service.create_private_key()
+    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key)
+
+    # create a private key to be used to make a CSR for the intermediate CA
+    inter_key = service.create_private_key()
+    csr = service._CryptographyService__create_csr(Subject(common_name="bar", country="CZ"), inter_key)
+
+    # sign the created CSR with root CA
+    inter_ca = service._CryptographyService__sign_csr(csr, root_ca, root_key)
+
+    inter_ca_printed = export_crt(inter_ca)
+
+    # assert fields
+    assert "Issuer: CN = foo" in inter_ca_printed
+    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
+
+
+def test_sign_csr_passphrase(service):
+    # create root CA and encrypt the private key of the root CA
+    root_key_passphrase = "barbaz"
+    root_key = service.create_private_key(passphrase=root_key_passphrase)
+    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
+
+    # create a private key to be used to make a CSR for the intermediate CA
+    inter_key = service.create_private_key()
+    csr = service._CryptographyService__create_csr(Subject(common_name="bar", country="CZ"), inter_key)
+
+    # sign the created CSR with root CA and specify root key passphrase
+    inter_ca = service._CryptographyService__sign_csr(csr, root_ca, root_key, issuer_key_pass=root_key_passphrase)
+
+    inter_ca_printed = export_crt(inter_ca)
+
+    # assert fields
+    assert "Issuer: CN = foo" in inter_ca_printed
+    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
+
+    # try to sign it using a wrong passphrase
+    with pytest.raises(CryptographyException) as e:
+        service._CryptographyService__sign_csr(csr, root_ca, root_key,
+                                               extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz.cert",
+                                               issuer_key_pass="bazbaz")
+    assert "bad decrypt" in e.value.message
+
+    # try to sign it without specifying a passphrase
+    with pytest.raises(CryptographyException) as e:
+        service._CryptographyService__sign_csr(csr, root_ca, root_key,
+                                               extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz.cert")
+    assert "bad decrypt" in e.value.message
+
+
+def test_sign_csr_extensions(service):
+    # create root CA and encrypt the private key of the root CA
+    root_key_passphrase = "barbaz"
+    root_key = service.create_private_key(passphrase=root_key_passphrase)
+    root_ca = service.create_sscrt(Subject(common_name="foo"), root_key, key_pass=root_key_passphrase)
+
+    # create a private key to be used to make a CSR for the intermediate CA
+    inter_key = service.create_private_key()
+    csr = service._CryptographyService__create_csr(Subject(common_name="bar", country="CZ"), inter_key)
+
+    # sign the created CSR with root CA and specify root key passphrase and specify extensions (AIA and CA)
+    inter_ca = service._CryptographyService__sign_csr(csr, root_ca, root_key,
+                                                      extensions="authorityInfoAccess = caIssuers;URI:bar.cz/baz/cert\nbasicConstraints=critical,CA:TRUE",
+                                                      issuer_key_pass=root_key_passphrase)
+
+    inter_ca_printed = export_crt(inter_ca)
+
+    # assert fields
+    assert "Issuer: CN = foo" in inter_ca_printed
+    assert "Subject: CN = bar, C = CZ" in inter_ca_printed
+
+    # assert extensions
+    expected_extensions = """        X509v3 extensions:
+            Authority Information Access: 
+                CA Issuers - URI:bar.cz/baz/cert
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE"""
+    assert expected_extensions in inter_ca_printed
diff --git a/tests/unit_tests/services/cryptography/verify_ca_test.py b/tests/unit_tests/services/cryptography/verify_ca_test.py
new file mode 100644
index 0000000..d3f68fe
--- /dev/null
+++ b/tests/unit_tests/services/cryptography/verify_ca_test.py
@@ -0,0 +1,31 @@
+import pytest
+
+from src.model.subject import Subject
+from src.services.cryptography import CryptographyException
+
+
+def test_verify_valid_ca(service):
+    # verify validation of valid certificates
+    private_key = service.create_private_key()
+    root_cert = service.create_sscrt(Subject(common_name="foo"), private_key)
+    child_cert = service.create_crt(Subject(common_name="Expired Foo"), private_key, root_cert, private_key, days=1)
+
+    assert service.verify_cert(root_cert)
+    assert service.verify_cert(child_cert)
+
+
+def test_verify_invalid_ca(service):
+    # test whether expired certificate will fail to get verified
+    private_key = service.create_private_key()
+    root_cert = service.create_sscrt(Subject(common_name="foo"), private_key)
+
+    expired_cert = service.create_crt(Subject(common_name="Expired Foo"), private_key, root_cert, private_key, days=0)
+
+    assert not service.verify_cert(expired_cert)
+
+
+def test_verify_invalid_cert_format(service):
+    # verify that certificate in invalid format raises <CryptographyException>
+
+    with pytest.raises(CryptographyException):
+        service.verify_cert("invalid cert")
