[VOL-3386] Add support for secure gRPC in openolt-agent

The init script of the openolt service may start with '--enable-tls <TLS_OPTION>' argument for the gRPC server.
Default is insecure with no '--enable-tls' argument.
The TLS capability depends upon the certificates stored at the keystore/ directory: 1. root.crt (CA public key), 2. server.crt (public key), 3.server.key (private key).
Four unit tests are added for the secure gRPC server which work with the keystore-test/ directory.
The certificates stored at the keystore-test/ directory are self-signed certificates, valid until Apr 11 23:16:58 2031 GMT.

Change-Id: I4d18a98a0193f501f922360c79f54b0fcedf14a5
diff --git a/agent/common/main.cc b/agent/common/main.cc
index b00b9b5..549bd59 100644
--- a/agent/common/main.cc
+++ b/agent/common/main.cc
@@ -88,7 +88,7 @@
         return 1;
     }
 
-    // Wait for successful activation before allowing VOLTHA to connect. 
+    // Wait for successful activation before allowing VOLTHA to connect.
     // This is necessary to allow the device topology to be dynamically
     // queried from driver after initialization and activation is complete.
     int maxTrials = 300;
@@ -107,7 +107,7 @@
     }
 
     sleep(2);
-    // Enable all PON interfaces. 
+    // Enable all PON interfaces.
     for (int i = 0; i < NumPonIf_(); i++) {
         status = EnablePonIf_(i);
         if (!status.ok()) {
@@ -145,7 +145,11 @@
           break;
        }
     }
-    RunServer(argc, argv);
+
+    if (!RunServer(argc, argv)) {
+        std::cerr << "FATAL: gRPC server creation failed\n";
+        return 2;
+    }
 
     return 0;
 }
diff --git a/agent/common/server.cc b/agent/common/server.cc
index 2b7a915..68cce10 100644
--- a/agent/common/server.cc
+++ b/agent/common/server.cc
@@ -27,6 +27,7 @@
 #include "server.h"
 #include "core.h"
 #include "state.h"
+#include "../src/core_utils.h"
 
 #include <grpc++/grpc++.h>
 #include <voltha_protos/openolt.grpc.pb.h>
@@ -348,8 +349,11 @@
     }
 };
 
-void RunServer(int argc, char** argv) {
+bool RunServer(int argc, char** argv) {
     std::string ipAddress = "0.0.0.0";
+    bool tls_enabled = false;
+    std::pair<grpc_ssl_client_certificate_request_type, bool> grpc_security;
+    std::shared_ptr<grpc::ServerCredentials> credentials;
 
     for (int i = 1; i < argc; ++i) {
         if(strcmp(argv[i-1], "--interface") == 0 || (strcmp(argv[i-1], "--intf") == 0)) {
@@ -358,6 +362,47 @@
         }
     }
 
+    for (int i = 1; i < argc; ++i) {
+        if (strcmp(argv[i-1], "--enable-tls") == 0) {
+            grpc_security = get_grpc_tls_option(argv[i]);
+            if (grpc_security.second) {
+                tls_enabled = true;
+            } else {
+                std::cerr << "unknown security option: \"" << argv[i-1] << " " << argv[i] << "\"\n";
+                return false;
+            };
+            break;
+        }
+    }
+
+    if (tls_enabled) {
+        std::string dir_cert{"./keystore"};
+        auto read_root_crt = read_from_txt_file(dir_cert + "/root.crt");
+        auto read_server_key = read_from_txt_file(dir_cert + "/server.key");
+        auto read_server_crt = read_from_txt_file(dir_cert + "/server.crt");
+
+        if (read_root_crt.second && read_server_key.second && read_server_crt.second) {
+            std::cout << "certificate files read successfully\n";
+        } else {
+            std::cerr << std::boolalpha << "certificate files read failed - root.crt: " << read_root_crt.second
+                                                                    << ", server.key: " << read_server_key.second
+                                                                    << ", server.crt: " << read_server_crt.second << '\n';
+            return false;
+        }
+
+        std::string root_crt = read_root_crt.first;
+        std::string server_key = read_server_key.first;
+        std::string server_crt = read_server_crt.first;
+
+        grpc::SslServerCredentialsOptions ssl_opts{grpc_security.first};
+        ssl_opts.pem_root_certs = root_crt;
+        grpc::SslServerCredentialsOptions::PemKeyCertPair keycert = {server_key, server_crt};
+        ssl_opts.pem_key_cert_pairs.push_back(keycert);
+        credentials = grpc::SslServerCredentials(ssl_opts);
+    } else {
+        credentials = grpc::InsecureServerCredentials();
+    }
+
     serverPort = ipAddress.append(":9191").c_str();
     OpenoltService service;
     std::string server_address(serverPort);
@@ -365,7 +410,7 @@
     ::ResourceQuota quota;
     quota.SetMaxThreads(GRPC_THREAD_POOL_SIZE);
     builder.SetResourceQuota(quota);
-    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+    builder.AddListeningPort(server_address, credentials);
     builder.RegisterService(&service);
 
     std::unique_ptr<Server> server(builder.BuildAndStart());
@@ -377,5 +422,11 @@
     std::cout << "Server listening on " << server_address
     << ", connection signature : " << signature << std::endl;
 
+#ifdef TEST_MODE
+    server->Shutdown();
+#else
     server->Wait();
+#endif
+
+    return true;
 }
diff --git a/agent/common/server.h b/agent/common/server.h
index f196fa3..56b8916 100644
--- a/agent/common/server.h
+++ b/agent/common/server.h
@@ -17,6 +17,6 @@
 #ifndef OPENOLT_SERVER_H_
 #define OPENOLT_SERVER_H_
 
-void RunServer(int argc, char** argv);
+bool RunServer(int argc, char** argv);
 
 #endif
diff --git a/agent/device/asfvolt16/mkdebian/debian/asfvolt16.postinst b/agent/device/asfvolt16/mkdebian/debian/asfvolt16.postinst
index b7ae471..ff4b68a 100644
--- a/agent/device/asfvolt16/mkdebian/debian/asfvolt16.postinst
+++ b/agent/device/asfvolt16/mkdebian/debian/asfvolt16.postinst
@@ -37,3 +37,5 @@
 /opt/bcm68620/svk_init.sh
 [ "A`cat ~/.bashrc| grep LD_LIBRARY_PATH`" = "A" ] && echo "export LD_LIBRARY_PATH=/broadcom:\$LD_LIBRARY_PATH" >> ~/.bashrc; . ~/.bashrc
 ldconfig /broadcom
+# create directory for certificates
+mkdir -p /broadcom/keystore/
diff --git a/agent/device/asgvolt64/mkdebian/debian/asgvolt64.postinst b/agent/device/asgvolt64/mkdebian/debian/asgvolt64.postinst
index c930f7b..46e2356 100644
--- a/agent/device/asgvolt64/mkdebian/debian/asgvolt64.postinst
+++ b/agent/device/asgvolt64/mkdebian/debian/asgvolt64.postinst
@@ -37,3 +37,5 @@
 /opt/bcm68620/svk_init.sh
 [ "A`cat ~/.bashrc| grep LD_LIBRARY_PATH`" = "A" ] && echo "export LD_LIBRARY_PATH=/broadcom:\$LD_LIBRARY_PATH" >> ~/.bashrc; . ~/.bashrc
 ldconfig /broadcom
+# create directory for certificates
+mkdir -p /broadcom/keystore/
diff --git a/agent/scripts/init.d/openolt b/agent/scripts/init.d/openolt
index e9a448b..27dfa0c 100755
--- a/agent/scripts/init.d/openolt
+++ b/agent/scripts/init.d/openolt
@@ -19,11 +19,44 @@
 USER="root"
 GROUP="root"
 
+# ------------------------------------------------------------------------------
 # If OLT is used in inband mode, inband interface name will be copied
 # to /etc/default/openolt file. Here inband interface is passed as argument
 # while running openolt service
 [ -r /etc/default/openolt ] && . /etc/default/openolt
 [ -z "gRPC_interface" ] || APPARGS="--interface $gRPC_interface"
+# ------------------------------------------------------------------------------
+GRPC_TLS_OPTION_A='GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE'
+# Server does not request client certificate.
+# The certificate presented by the client is not checked by the server at all. (A client may present a self signed or signed certificate or not present a certificate at all and any of those option would be accepted)
+
+GRPC_TLS_OPTION_B='GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY'
+# Server requests client certificate but does not enforce that the client presents a certificate.
+# If the client presents a certificate, the client authentication is left to the application (the necessary metadata will be available to the application via authentication context properties, see grpc_auth_context).
+# The client's key certificate pair must be valid for the SSL connection to be established.
+
+GRPC_TLS_OPTION_C='GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY'
+# Server requests client certificate but does not enforce that the client presents a certificate.
+# If the client presents a certificate, the client authentication is done by the gRPC framework. (For a successful connection the client needs to either present a certificate that can be verified against the root certificate configured by the server or not present a certificate at all)
+# The client's key certificate pair must be valid for the SSL connection to be established.
+
+GRPC_TLS_OPTION_D='GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY'
+# Server requests client certificate and enforces that the client presents a certificate.
+# If the client presents a certificate, the client authentication is left to the application (the necessary metadata will be available to the application via authentication context properties, see grpc_auth_context).
+# The client's key certificate pair must be valid for the SSL connection to be established.
+
+GRPC_TLS_OPTION_E='GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY'
+# Server requests client certificate and enforces that the client presents a certificate.
+# The certificate presented by the client is verified by the gRPC framework. (For a successful connection the client needs to present a certificate that can be verified against the root certificate configured by the server)
+# The client's key certificate pair must be valid for the SSL connection to be established.
+
+GRPC_TLS_OPTION_Z='' # INSECURE
+
+# choose one of the above six options with the last letter
+GRPC_TLS_OPTION=$GRPC_TLS_OPTION_Z
+
+[ $GRPC_TLS_OPTION ] && APPARGS="$APPARGS --enable-tls $GRPC_TLS_OPTION"
+# ------------------------------------------------------------------------------
 
 # Include functions
 set -e
@@ -52,7 +85,7 @@
   while test -d /proc/$(cat /var/run/$NAME.pid); do
     killtree $(cat /var/run/$NAME.pid) 15
     sleep 0.5
-  done 
+  done
   [ -z `cat /var/run/$NAME.pid 2>/dev/null` ] || rm /var/run/$NAME.pid
   printf "done\n"
 }
diff --git a/agent/src/core_utils.cc b/agent/src/core_utils.cc
index 59c7cdc..0153078 100644
--- a/agent/src/core_utils.cc
+++ b/agent/src/core_utils.cc
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
+#include <fstream>
+#include <sstream>
 #include "core_utils.h"
 
+// save the TLS option
+static std::string tls_option_arg{};
+
 std::string serial_number_to_str(bcmolt_serial_number* serial_number) {
 #define SERIAL_NUMBER_SIZE 12
     char buff[SERIAL_NUMBER_SIZE+1];
@@ -1673,3 +1678,48 @@
     }
     return false;
 }
+
+std::pair<grpc_ssl_client_certificate_request_type, bool> get_grpc_tls_option(const char* tls_option) {
+    static std::map<std::string,grpc_ssl_client_certificate_request_type> grpc_security_option_map = {{"GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE",
+                                                                                                        grpc_ssl_client_certificate_request_type::GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE},
+                                                                                                      {"GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY",
+                                                                                                        grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY},
+                                                                                                      {"GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY",
+                                                                                                        grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY},
+                                                                                                      {"GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY",
+                                                                                                        grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY},
+                                                                                                      {"GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY",
+                                                                                                        grpc_ssl_client_certificate_request_type::GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY}};
+
+    auto it = grpc_security_option_map.find(tls_option);
+    if (it == grpc_security_option_map.end()) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "invalid gRPC Server security option: %s\n", tls_option);
+        return {grpc_ssl_client_certificate_request_type::GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, false};
+    } else {
+        OPENOLT_LOG(INFO, openolt_log_id, "valid gRPC Server security option: %s\n", tls_option);
+        tls_option_arg = std::string{tls_option};
+        return {it->second, true};
+    }
+}
+
+const std::string &get_grpc_tls_option() {
+    return tls_option_arg;
+}
+
+bool is_grpc_secure() {
+    return !tls_option_arg.empty();
+}
+
+std::pair<std::string, bool> read_from_txt_file(const std::string& file_name) {
+    std::ifstream in_file(file_name);
+
+    if (!in_file.is_open()) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "error opening file '%s'\n", file_name.c_str());
+        return {"", false};
+    }
+
+    std::stringstream buffer;
+    buffer << in_file.rdbuf();
+
+    return {buffer.str(), in_file.good()};
+}
diff --git a/agent/src/core_utils.h b/agent/src/core_utils.h
index 0f7cfe7..3d4668c 100644
--- a/agent/src/core_utils.h
+++ b/agent/src/core_utils.h
@@ -25,6 +25,7 @@
 #include "core.h"
 #include "core_data.h"
 #include "error_format.h"
+#include <grpc/grpc_security_constants.h>
 
 extern "C"
 {
@@ -117,4 +118,8 @@
 const device_flow_params* get_device_flow_params(uint64_t voltha_flow_id);
 trap_to_host_packet_type get_trap_to_host_packet_type(const ::openolt::Classifier& classifier);
 bool is_packet_allowed(bcmolt_access_control_receive_eth_packet_data *data, int32_t gemport_id);
+std::pair<grpc_ssl_client_certificate_request_type, bool> get_grpc_tls_option(const char* tls_option);
+const std::string &get_grpc_tls_option();
+bool is_grpc_secure();
+std::pair<std::string, bool> read_from_txt_file(const std::string& file_name);
 #endif // OPENOLT_CORE_UTILS_H_
diff --git a/agent/test/keystore-test/root.crt b/agent/test/keystore-test/root.crt
new file mode 100644
index 0000000..2ae357b
--- /dev/null
+++ b/agent/test/keystore-test/root.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEDTCCAvWgAwIBAgIJALTkUm+wi0Y9MA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD
+VQQGEwJUUjERMA8GA1UECAwISXN0YW5idWwxETAPBgNVBAcMCElzdGFuYnVsMQ8w
+DQYDVQQKDAZBUkdFTEExDTALBgNVBAsMBFNFQkExGzAZBgNVBAMMEnNlYmEuYXJn
+ZWxhLmNvbS50cjEqMCgGCSqGSIb3DQEJARYbbmV0c2lhLmRldm9wc0BhcmdlbGEu
+Y29tLnRyMB4XDTIxMDQxMzIzMTY1OFoXDTMxMDQxMTIzMTY1OFowgZwxCzAJBgNV
+BAYTAlRSMREwDwYDVQQIDAhJc3RhbmJ1bDERMA8GA1UEBwwISXN0YW5idWwxDzAN
+BgNVBAoMBkFSR0VMQTENMAsGA1UECwwEU0VCQTEbMBkGA1UEAwwSc2ViYS5hcmdl
+bGEuY29tLnRyMSowKAYJKoZIhvcNAQkBFhtuZXRzaWEuZGV2b3BzQGFyZ2VsYS5j
+b20udHIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwos2j7GWNExJZ
+PgeOURaP/9JcV+1SC5aDqG4UwLlAGSPoQUkf/0LjgMde9ZeRe8rugGXW39v2cbWm
+eb5TNyTwWGED2wEMVijzBgnYTYA6nXTxz+XAvxVu/x6fHtNMOqHGiewN0S1eY7bz
+rE1zq6SeunDJGCW6pIa4aNMq7/ngDsPrSc6f1pKZpCgrNSW/LnGdgTB2HkaroUr8
+vy3OWZ0FG042HjT7q+MjEgqGLDl7VkBFrJn2gp4sfgX1WSM/9brhcaVZ/puagaY8
+Ju2Dq3foXDW3xgW9y22mk/3cQpRGRSad9+ZAWb9ZPyp5lcUaqpMuYyiFoGctdQT8
+s1LMbPCnAgMBAAGjUDBOMB0GA1UdDgQWBBTpfNEjdHBqnzSDYXuwrFCnZ7P1/zAf
+BgNVHSMEGDAWgBTpfNEjdHBqnzSDYXuwrFCnZ7P1/zAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4IBAQBorTfS9g2xi9kO42nDTs+VRv64j09cJyZl5BFoivFO
+SV2O64ubp6YEaKjqUnPuzs7D3j8cjalqeIeD2tFJHRrv8XADlgivEtTk2o5sCEJx
+66eOAXeqlLPHK9dt3IxKI5kPBTGKQHw2uNG8VOsRlq2DB798ueWxzUWPpxjhSFL/
+YP/o3pEWxit5SirBAoaRZaccjPHz2c/4IfGuoPOXun+qKvt/ic2QRm23e62Wb/Do
+eugVy1Zi0aAOenoJaNuiZEX7l2qZ4RssGheJxWdEOzGZ9YxpS7WseKgxufQ9RmoR
+4J4bU/hVy2su6+cqn7Q5YchcJjfuT181yq+/UFgpvMTa
+-----END CERTIFICATE-----
diff --git a/agent/test/keystore-test/server.crt b/agent/test/keystore-test/server.crt
new file mode 100644
index 0000000..8186f31
--- /dev/null
+++ b/agent/test/keystore-test/server.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDzTCCArWgAwIBAgIJAILLZCQ2zGU7MA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD
+VQQGEwJUUjERMA8GA1UECAwISXN0YW5idWwxETAPBgNVBAcMCElzdGFuYnVsMQ8w
+DQYDVQQKDAZBUkdFTEExDTALBgNVBAsMBFNFQkExGzAZBgNVBAMMEnNlYmEuYXJn
+ZWxhLmNvbS50cjEqMCgGCSqGSIb3DQEJARYbbmV0c2lhLmRldm9wc0BhcmdlbGEu
+Y29tLnRyMB4XDTIxMDQxMzIzMTcyNFoXDTMxMDQxMTIzMTcyNFowUTELMAkGA1UE
+BhMCQ0ExDTALBgNVBAgMBE5vbmUxCzAJBgNVBAcMAk5CMQ0wCwYDVQQKDAROb25l
+MRcwFQYDVQQDDA4xOTIuMTY4LjMwLjIyMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBANh3OVBIS7kFcOda1dA8+423RRhfrwsL3AHjthZ6+f9TYSb0BcFv
+VQKwGRWXVFZsX3q6yivi8zq1AoLUYd7Ir0W+UFuP17unMeKij3PjPMwc42aL5lfs
+7b1VVG1yk4CoMHdGs/gpbLQwAvhwvaovI1SReCW8ddehJ6P50P8ACVmklK08W9Hm
+mdzAdq/HUw/oaCi5kNtFP2aqXlOofYaJ6aYRLaGYNpgvj9SiGo62SB0VRteik4Pd
+HjjiTkWUcEblUC89UfQCcqGUG4vXoNhaS2AmMCg+MgPlaWRyUT6q9uXQ5CnLSD9r
+lDcSNsHHwapMf1lWPBPB2r0EkQpbazD+WWsCAwEAAaNcMFowHwYDVR0jBBgwFoAU
+6XzRI3Rwap80g2F7sKxQp2ez9f8wCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwHwYD
+VR0RBBgwFoIOMTkyLjE2OC4zMC4yMjGHBMCoHt0wDQYJKoZIhvcNAQELBQADggEB
+AIHUdvm/njSX5wQzegQeq7Axo+o6HfhJFH5ot1B0rtLG3/SkWOj+t9gqEeJxLYCI
+Wz+EhUupISZ/Vb8KtSZgLPFQ+H61+x945zT0zE61Wh3hKJOK1HZVbMhtWHbzaqEa
+nPQniw9wCKflnUgJUqYGb3rBFqmCEKYXvcyQp63zUmnAIJze+liEXVmHpCPPR+Jo
+CcoSXMR7iCl6s1hpkSB72CxhvcZi6zfCkyVTmxDfwVTtciqjQEr8gC2ufff7qRHM
+ZRrU9NtiMQqu5yZQsQiFGMDU68sHYz3uQQSjaqih+DcPLf7Pg1qFrrbbq7C0Znmw
+rCp11vZTwWKj3fg/lR7AAq4=
+-----END CERTIFICATE-----
diff --git a/agent/test/keystore-test/server.key b/agent/test/keystore-test/server.key
new file mode 100644
index 0000000..371ceeb
--- /dev/null
+++ b/agent/test/keystore-test/server.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYdzlQSEu5BXDn
+WtXQPPuNt0UYX68LC9wB47YWevn/U2Em9AXBb1UCsBkVl1RWbF96usor4vM6tQKC
+1GHeyK9FvlBbj9e7pzHioo9z4zzMHONmi+ZX7O29VVRtcpOAqDB3RrP4KWy0MAL4
+cL2qLyNUkXglvHXXoSej+dD/AAlZpJStPFvR5pncwHavx1MP6GgouZDbRT9mql5T
+qH2GiemmES2hmDaYL4/UohqOtkgdFUbXopOD3R444k5FlHBG5VAvPVH0AnKhlBuL
+16DYWktgJjAoPjID5WlkclE+qvbl0OQpy0g/a5Q3EjbBx8GqTH9ZVjwTwdq9BJEK
+W2sw/llrAgMBAAECggEAJPrZM7nmFcm0LBH8jQKeBuvURgGyqbRw9XGtXdHMe64G
+3ty5Tv5yC2+CGYoswkbpWNIoT68J1nGt6CPYRHMMXmHQ4JOGS2yYvRsAXs/nRwd4
+YcBsrYCwbLPzJG96e3RAM2BExpRtGatKFp9MB5Ld+kiPugKkLx4842p+JdIfxsxi
+lggzGkneu95yJnTS2i/BcKUAVO2HM1DKOtfgIofPCT4tgZpboa0p7GKa1TtqqdTT
+Zk4t6qVh3MSRYcQe2pMXZJgOAJupAzXIAYoafw+io22dt2mDqLhb9YRxCIabhYif
+Oz8e4b9O8hvJcTs0/2hYUW4vtDQzlFCeSaC5fuk5oQKBgQDw04BnrkQ84kPZ0PrN
+e8zWk2jAqBmiyzgykMbUnX34CImINTjwgqhgKjMFepqxGwsQN7YHyu5Jq7I1sEYm
+LSrQGDa8zqTifcSkyHq7k+TFM371/OCW+xAUITrzd/KZdBiH2syAePHUO/02G7up
+aIUjvaB2Qp/qVPe3MzDkVGvDNQKBgQDmGsp4VdL/SEsWCSs+5tIK2gnok2+/V9s5
+fSPPROABsEBtLf+rJeGmh6qkOBeRZnncAajza6oKMKo9NLA68qFNs7Yg+ZvnDcu7
+X+VyRiXp+uR65oNPEhIMO8x7NGPx+VqYZtAWI0I3lGZpzkZ8zfVHFJCFpd+ieDv8
+RSAHX3ueHwKBgGjSxrtaYR1XJ01x5xj14A0uEJR7Ft2DMyzfU4xMGP6TSLne4K/f
+T0a8V4T0/sxEBybB+RufOuUaNPGljoMjedUmFP1NvPtQ3v0SvklTcGpdpc+QiHlv
+QmpgpHZBKXmdzOelVwo8mpZUnjylCaQNeJY7/dI74btvzHsTbx6TmGxZAoGBAOER
+3W8cy3hl1wPjzggFr/drU/vIkqo/HjA6Jherj8w3AJ2KO6TFNdU0qAVe1DalXJaE
+jSQj8DttZGbfrWzLPFmLaZ8RZ5v104wgfYZr9NPLU0afSFrEGyEaMKVmFkhtlV6y
+WeD9ddx1bEMbv7h9n+d5xu7i0z7QiiPz3SM5EuoTAoGBAJKBvQx7ZtW2QMgdwxdF
+2Yfv7qmifUcsi7vLNeEQGSBa6s7SXPLrUaODSIKL0lIgIsxQelxJj8zfDkqVEWqO
+8b0g+v9FAqQjgB90mALPNcdS/DCuQ2Vdx0ertkGjUetWaAhuHspZi79IOG+2j9iv
+pvZKgzwl2RaJTlr77Qz6lsa4
+-----END PRIVATE KEY-----
diff --git a/agent/test/src/test_core.cc b/agent/test/src/test_core.cc
index bce275e..55297b9 100644
--- a/agent/test/src/test_core.cc
+++ b/agent/test/src/test_core.cc
@@ -18,6 +18,7 @@
 #include "bal_mocker.h"
 #include "core.h"
 #include "core_data.h"
+#include "server.h"
 #include <future>
 using namespace testing;
 using namespace std;
@@ -3239,3 +3240,87 @@
     Status status = GetLogicalOnuDistance_(pon_ni, onu_id, onu_logical_distance);
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
+
+////////////////////////////////////////////////////////////////////////////
+// For testing Secure Server functionality
+////////////////////////////////////////////////////////////////////////////
+
+class TestSecureServer : public Test {
+    protected:
+        virtual void SetUp() {}
+        virtual void TearDown() {}
+};
+
+TEST_F(TestSecureServer, StartInsecureServer) {
+    // const to prevent the following warning:
+    // warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
+    const char *args[] = {"./openolt"};
+    int argc = sizeof(args) / sizeof(args[0]);
+    char **argv = const_cast<char**>(args);
+
+    bool ok = RunServer(argc, argv);
+
+    ASSERT_TRUE(ok);
+
+    OPENOLT_LOG(INFO, openolt_log_id, "insecure gRPC server has been started and shut down successfully\n");
+}
+
+TEST_F(TestSecureServer, StartWithInvalidTLSOption) {
+    const char *args[] = {"./openolt", "--enable-tls", "DUMMY_GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE"};
+    int argc = sizeof(args) / sizeof(args[0]);
+    char **argv = const_cast<char**>(args);
+
+    bool ok = RunServer(argc, argv);
+
+    ASSERT_FALSE(ok);
+
+    OPENOLT_LOG(INFO, openolt_log_id, "secure gRPC server could not be started due to invalid TLS option\n");
+}
+
+TEST_F(TestSecureServer, CertificatesAreMissing) {
+    const char *args[] = {"./openolt", "--enable-tls", "GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE"};
+    int argc = sizeof(args) / sizeof(args[0]);
+    char **argv = const_cast<char**>(args);
+    const std::string cmd = "exec [ -d './keystore' ] && rm -rf './keystore'";
+
+    int res = std::system(cmd.c_str());
+    if (res == 0) {
+        std::cout << "directory ./keystore is deleted\n";
+    } else {
+        std::cout << "directory ./keystore is not existing\n";
+    }
+
+    bool ok = RunServer(argc, argv);
+
+    ASSERT_FALSE(ok);
+
+    OPENOLT_LOG(INFO, openolt_log_id, "secure gRPC server could not be started due to missing certificates\n");
+}
+
+TEST_F(TestSecureServer, StartWithValidTLSOption) {
+    const char *args[] = {"./openolt", "--enable-tls", "GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE"};
+    int argc = sizeof(args) / sizeof(args[0]);
+    char **argv = const_cast<char**>(args);
+    const std::string cmd_1 = "exec cp -r ./keystore-test ./keystore";
+    const std::string cmd_2 = "exec rm -rf './keystore'";
+
+    int res = std::system(cmd_1.c_str());
+    if (res == 0) {
+        std::cout << "directory ./keystore is copied from ./keystore-test\n";
+
+        bool ok = RunServer(argc, argv);
+        ASSERT_TRUE(ok);
+
+        OPENOLT_LOG(INFO, openolt_log_id, "secure gRPC server has been started with the given certificates and TLS options, and shut down successfully\n");
+
+        res = std::system(cmd_2.c_str());
+        if (res == 0) {
+            std::cout << "directory ./keystore is deleted\n";
+        } else {
+            std::cerr << "directory ./keystore could not be deleted\n";
+        }
+    } else {
+        std::cerr << "directory ./keystore could not be prepared, err: " << res << '\n';
+        FAIL();
+    }
+}