commit 1d8ff0a3b99d0d44e37ed0bae0cd10cc20894a5f
Author: Stanislav Král <stanislav.kral3@gmail.com>
Date:   Sat May 1 06:49:24 2021 +0200

    Re #8708 - Added a new REST API endpoint used for generating a PKCS12 identities of certificates

diff --git a/app.py b/app.py
index 03b877f..4534460 100644
--- a/app.py
+++ b/app.py
@@ -85,6 +85,11 @@ def get_ocsp_of_issuer_post(id, crl_ocsp_controller: CrlOcspController):
     return crl_ocsp_controller.get_ocsp_from_der(id, request.data)
 
 
+@app.route('/api/certificates/<id>/identity', methods=["POST"])
+def generate_certificate_pkcs_identity(id, certificate_controller: CertController):
+    return certificate_controller.generate_certificate_pkcs_identity(id)
+
+
 def initialize_app(application) -> bool:
     """
     Initializes the application
diff --git a/src/controllers/certificates_controller.py b/src/controllers/certificates_controller.py
index 4979c11..8763bd3 100644
--- a/src/controllers/certificates_controller.py
+++ b/src/controllers/certificates_controller.py
@@ -3,7 +3,7 @@ from datetime import datetime
 from itertools import chain
 from json import JSONDecodeError
 
-from flask import request
+from flask import request, Response
 from injector import inject
 
 from src.constants import CA_ID, \
@@ -37,6 +37,8 @@ ISSUED_BY = "issuedby"
 STATUS = "status"
 REASON = "reason"
 REASON_UNDEFINED = "unspecified"
+NAME = "name"
+PASSWORD = "password"
 
 E_NO_ISSUER_FOUND = {"success": False, "data": "No certificate authority with such unique ID exists."}
 E_NO_CERTIFICATES_FOUND = {"success": False, "data": "No such certificate found."}
@@ -48,6 +50,8 @@ E_CORRUPTED_DATABASE = {"success": False, "data": "Internal server error (corrup
 E_GENERAL_ERROR = {"success": False, "data": "Internal server error (unknown origin)."}
 E_MISSING_PARAMETERS = {"success": False, "data": "Invalid request, missing parameters."}
 E_WRONG_PARAMETERS = {"success": False, "data": "Invalid request, wrong parameters."}
+E_IDENTITY_NAME_NOT_SPECIFIED = {"success": False, "data": "Invalid request, missing identity name."}
+E_IDENTITY_PASSWORD_NOT_SPECIFIED = {"success": False, "data": "Invalid request, missing identity password."}
 
 
 class CertController:
@@ -591,4 +595,61 @@ class CertController:
             Logger.error(f"Internal server error (unknown origin).")
             return E_GENERAL_ERROR, C_INTERNAL_SERVER_ERROR
 
-        return {"success": True, "data": "The certificate and its descendants have been successfully deleted."}
\ No newline at end of file
+        return {"success": True, "data": "The certificate and its descendants have been successfully deleted."}
+
+    def generate_certificate_pkcs_identity(self, id):
+        """
+        Generates a PKCS12 identity (including the chain of trust) of the certificate given by the specified ID.
+        Response is of application/x-pkcs12 type.
+
+        :param id: ID of a certificate whose PKCS12 identity should be generated
+        :type id: int
+
+        :rtype: Response
+        """
+
+        Logger.info(f"\n\t{request.referrer}"
+                    f"\n\t{request.method}   {request.path}   {request.scheme}"
+                    f"\n\tCertificate ID = {id}")
+
+        # try to parse the supplied ID
+        try:
+            v = int(id)
+        except ValueError:
+            Logger.error(f"Invalid request, wrong parameters 'id'[{id}] (expected integer).")
+            return E_WRONG_PARAMETERS, C_BAD_REQUEST
+
+        # find a certificate using the given ID
+        cert = self.certificate_service.get_certificate(v)
+
+        if request.is_json:                                                         # accept JSON only
+            body = request.get_json()
+
+            # check whether the request is well formed meaning that it contains all required fields
+            if NAME not in body.keys():
+                return E_IDENTITY_NAME_NOT_SPECIFIED, C_BAD_REQUEST
+
+            if PASSWORD not in body.keys():
+                return E_IDENTITY_PASSWORD_NOT_SPECIFIED, C_BAD_REQUEST
+
+            # parse required fields from the request
+            identity_name = body[NAME]
+            identity_password = body[PASSWORD]
+
+            # check whether a certificated specified by the given ID exists
+            if cert is None:
+                Logger.error(f"No such certificate found 'ID = {v}'.")
+                return E_NO_CERTIFICATES_FOUND, C_NOT_FOUND
+            else:
+                # try to load it's private key
+                key = self.key_service.get_key(cert.private_key_id)
+                if key is None:
+                    Logger.error(
+                        f"The private key 'ID = {cert.private_key_id}'of the certificate 'ID = {cert.certificate_id}' does not exist.")
+                    return E_NO_CERTIFICATES_FOUND, C_INTERNAL_SERVER_ERROR
+                else:
+                    # generate PKCS12 identity
+                    identity_byte_array = self.certificate_service.generate_pkcs_identity(cert.certificate_id, key,
+                                                                                          identity_name,
+                                                                                          identity_password)
+                    return Response(identity_byte_array, mimetype='application/x-pkcs12')
