From b4d43f50cbd914e1add84b490d9879319d7afeaa Mon Sep 17 00:00:00 2001
From: svetaro <sveta@skalelabs.com>
Date: Fri, 10 Jan 2020 17:40:24 +0200
Subject: [PATCH] SKALE-1762 Add csr manager server

---
 CSRManagerServer.cpp      | 124 ++++++++++++++++++++++++++++++++++
 CSRManagerServer.h        |  32 +++++++++
 LevelDB.cpp               |  43 +++++++++++-
 LevelDB.h                 |  10 ++-
 Makefile.am               |  12 +++-
 SGXRegistrationServer.cpp | 136 +++++++++++++++++++++++---------------
 SGXRegistrationServer.h   |   3 +-
 ServerInit.cpp            |  11 +--
 cert/create_client_cert   |   6 +-
 cert_util.cpp             |  64 ++++++++++++++++++
 sgxwallet.c               |  19 +++---
 sgxwallet_common.h        |   8 ++-
 stubclient.h              |  28 ++++++++
 13 files changed, 420 insertions(+), 76 deletions(-)
 create mode 100644 CSRManagerServer.cpp
 create mode 100644 CSRManagerServer.h
 create mode 100644 cert_util.cpp

diff --git a/CSRManagerServer.cpp b/CSRManagerServer.cpp
new file mode 100644
index 0000000..30a247a
--- /dev/null
+++ b/CSRManagerServer.cpp
@@ -0,0 +1,124 @@
+//
+// Created by kladko on 12/24/19.
+//
+
+#include "CSRManagerServer.h"
+#include "RPCException.h"
+#include "sgxwallet_common.h"
+
+#include <iostream>
+#include <fstream>
+
+#include <jsonrpccpp/server/connectors/httpserver.h>
+
+
+CSRManagerServer *cs = nullptr;
+jsonrpc::HttpServer *hs3 = nullptr;
+
+
+CSRManagerServer::CSRManagerServer(AbstractServerConnector &connector,
+    serverVersion_t type):abstractCSRManagerServer(connector, type){}
+
+
+Json::Value GetUnsignedCSRsImpl(){
+  std::cerr << "Enter GetUnsignedCSRsImpl" << std::endl;
+  Json::Value result;
+  result["status"] = 0;
+  result["errorMessage"] = "";
+  //result["hashes"] =;
+
+  try{
+    std::vector<std::string> hashes_vect = csrDb->writeKeysToVector1(MAX_CSR_NUM);
+    //std::cerr << " vector size is " << hashes_vect.size() << std::endl;
+    for (int i = 0; i < hashes_vect.size(); i++){
+      //std::cerr << " vector element is " << hashes_vect.at(i) << std::endl;
+      result["hashes"][i] = hashes_vect.at(i);
+    }
+  } catch (RPCException &_e) {
+    std::cerr << " err str " << _e.errString << std::endl;
+    result["status"] = _e.status;
+    result["errorMessage"] = _e.errString;
+
+  }
+
+  return result;
+}
+
+Json::Value SignByHashImpl(const std::string& hash, int status){
+  Json::Value result;
+  result["errorMessage"] = "";
+
+  try{
+    if ( !(status == 0 || status == 2)){
+      throw RPCException(-111, "Invalid csr status");
+    }
+
+    std::string csr_db_key = "CSR:HASH:" + hash;
+    std::shared_ptr<std::string> csr_ptr = csrDb->readString(csr_db_key);
+
+    if (status == 0) {
+      std::string csr_name = "cert/" + hash + ".csr";
+      std::ofstream outfile(csr_name);
+      outfile << *csr_ptr << std::endl;
+      outfile.close();
+      if (access(csr_name.c_str(), F_OK) != 0) {
+        throw RPCException(FILE_NOT_FOUND, "Csr does not exist");
+      }
+
+      std::string signClientCert = "cd cert && ./create_client_cert " + hash;
+
+      if (system(signClientCert.c_str()) == 0) {
+        std::cerr << "CLIENT CERTIFICATE IS SUCCESSFULLY GENERATED" << std::endl;
+      } else {
+        std::cerr << "CLIENT CERTIFICATE GENERATION FAILED" << std::endl;
+        csrDb->deleteKey(csr_db_key);
+        std::string status_db_key = "CSR:HASH:" + hash + "STATUS:";
+        csrStatusDb->deleteKey(status_db_key);
+        csrStatusDb->writeDataUnique(status_db_key, "-1");
+        throw RPCException(FAIL_TO_CREATE_CERTIFICATE, "CLIENT CERTIFICATE GENERATION FAILED");
+        //exit(-1);
+      }
+    }
+
+    csrDb->deleteKey(csr_db_key);
+    std::string status_db_key = "CSR:HASH:" + hash + "STATUS:";
+    csrStatusDb->deleteKey(status_db_key);
+    csrStatusDb->writeDataUnique(status_db_key, std::to_string(status));
+
+    result["status"] = status;
+
+  } catch (RPCException &_e) {
+    std::cerr << " err str " << _e.errString << std::endl;
+    result["status"] = _e.status;
+    result["errorMessage"] = _e.errString;
+  }
+
+  return result;
+}
+
+
+Json::Value CSRManagerServer::GetUnsignedCSRs(){
+  std::lock_guard<std::recursive_mutex> lock(m);
+  return GetUnsignedCSRsImpl();
+}
+
+Json::Value CSRManagerServer::SignByHash(const std::string& hash, int status){
+   std::lock_guard<std::recursive_mutex> lock(m);
+   return SignByHashImpl(hash, status);
+}
+
+int init_csrmanager_server(){
+  hs3 = new jsonrpc::HttpServer(BASE_PORT + 2);
+  hs3 -> BindLocalhost();
+  cs = new CSRManagerServer(*hs3, JSONRPC_SERVER_V2); // server (json-rpc 2.0)
+
+  if (!cs->StartListening()) {
+    std::cerr << "CSR manager server could not start listening" << std::endl;
+    exit(-1);
+  }
+  else {
+    std::cerr << "CSR manager server started on port " << BASE_PORT + 2 << std::endl;
+  }
+  std::cerr << "CSR manager inited" << std::endl;
+  return 0;
+};
\ No newline at end of file
diff --git a/CSRManagerServer.h b/CSRManagerServer.h
new file mode 100644
index 0000000..d67abe4
--- /dev/null
+++ b/CSRManagerServer.h
@@ -0,0 +1,32 @@
+//
+// Created by kladko on 12/24/19.
+//
+
+#ifndef SGXD_CSRMANAGERSERVER_H
+#define SGXD_CSRMANAGERSERVER_H
+
+#include "abstractCSRManagerServer.h"
+#include "LevelDB.h"
+
+#include <mutex>
+
+using namespace jsonrpc;
+
+class CSRManagerServer : public abstractCSRManagerServer {
+
+  std::recursive_mutex m;
+
+  public:
+
+  CSRManagerServer(AbstractServerConnector &connector, serverVersion_t type);
+
+  virtual Json::Value GetUnsignedCSRs();
+  virtual Json::Value SignByHash(const std::string& hash, int status);
+};
+
+extern int init_csrmanager_server();
+
+
+
+
+#endif //SGXD_CSRMANAGERSERVER_H
diff --git a/LevelDB.cpp b/LevelDB.cpp
index fa7bd05..aa00fca 100644
--- a/LevelDB.cpp
+++ b/LevelDB.cpp
@@ -42,6 +42,9 @@ static ReadOptions readOptions;
 
 
 LevelDB* levelDb = nullptr;
+LevelDB* csrDb = nullptr;
+LevelDB* csrStatusDb = nullptr;
+
 
 std::shared_ptr<std::string> LevelDB::readString(const std::string &_key) {
 
@@ -55,6 +58,10 @@ std::shared_ptr<std::string> LevelDB::readString(const std::string &_key) {
 
     auto status = db->Get(readOptions, _key, &*result);
 
+//    if (result == nullptr) {
+//      throw RPCException(KEY_SHARE_DOES_NOT_EXIST, "Data with this name does not exist");
+//    }
+
     std::cerr << "key to read from db: " << _key <<std::endl;
 
     throwExceptionOnError(status);
@@ -166,8 +173,6 @@ void LevelDB::throwExceptionOnError(Status _status) {
 
 uint64_t LevelDB::visitKeys(LevelDB::KeyVisitor *_visitor, uint64_t _maxKeysToVisit) {
 
-    std::lock_guard<std::recursive_mutex> lock(mutex);
-
     uint64_t readCounter = 0;
 
     leveldb::Iterator *it = db->NewIterator(readOptions);
@@ -184,6 +189,40 @@ uint64_t LevelDB::visitKeys(LevelDB::KeyVisitor *_visitor, uint64_t _maxKeysToVi
     return readCounter;
 }
 
+std::vector<std::string> LevelDB::writeKeysToVector1(uint64_t _maxKeysToVisit){
+  uint64_t readCounter = 0;
+  std::vector<std::string> keys;
+
+  leveldb::Iterator *it = db->NewIterator(readOptions);
+  for (it->SeekToFirst(); it->Valid(); it->Next()) {
+    std::string cur_key(it->key().data(), it->key().size());
+    keys.push_back(cur_key);
+   // keys.push_back(it->key().data());
+    readCounter++;
+    if (readCounter >= _maxKeysToVisit) {
+      break;
+    }
+  }
+
+  delete it;
+
+  return keys;
+}
+
+void LevelDB::writeDataUnique(const std::string & Name, const std::string &value) {
+
+  auto key = Name;
+
+  if (readString(Name) != nullptr) {
+    std::cerr << "name " << Name << " already exists" << std::endl;
+    throw RPCException(KEY_SHARE_ALREADY_EXISTS, "Data with this name already exists");
+  }
+
+  writeString(key, value);
+  std::cerr << Name << " is written to db " << std::endl;
+}
+
+
 LevelDB::LevelDB(std::string &filename) {
 
 
diff --git a/LevelDB.h b/LevelDB.h
index 1fdcabc..380932c 100644
--- a/LevelDB.h
+++ b/LevelDB.h
@@ -28,6 +28,7 @@
 #include <memory>
 #include <string>
 #include <mutex>
+#include <vector>
 
 namespace leveldb {
     class DB;
@@ -49,7 +50,7 @@ public:
 
     void writeString(const std::string &key1, const std::string &value1);
 
-
+    void writeDataUnique(const std::string & Name, const std::string &value);
 
     void writeByteArray(const char *_key, size_t _keyLen, const char *value,
                         size_t _valueLen);
@@ -80,10 +81,13 @@ public:
     class KeyVisitor {
     public:
         virtual void visitDBKey(const char* _data) = 0;
+        virtual void writeDBKeysToVector(const char* _data, std::vector<const char*> & keys_vect) {}
     };
 
     uint64_t visitKeys(KeyVisitor* _visitor, uint64_t _maxKeysToVisit);
 
+    std::vector<std::string> writeKeysToVector1(uint64_t _maxKeysToVisit);
+
     virtual ~LevelDB();
 
 
@@ -92,4 +96,8 @@ public:
 
 extern LevelDB* levelDb;
 
+extern LevelDB* csrDb;
+
+extern LevelDB* csrStatusDb;
+
 #endif
\ No newline at end of file
diff --git a/Makefile.am b/Makefile.am
index a9188ef..13cad84 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -57,7 +57,7 @@ CLEANFILES = $(COMMON_ENCLAVE_SRC) secure_enclave.edl \
 
 ## The build target
 
-bin_PROGRAMS =  sgxwallet testw
+bin_PROGRAMS =  sgxwallet testw cert_util
 
 
 ## You can't use $(wildcard ...) with automake so all source files
@@ -66,7 +66,7 @@ bin_PROGRAMS =  sgxwallet testw
 COMMON_SRC = sgx_stub.c sgx_detect_linux.c create_enclave.c oc_alloc.c
 COMMON_ENCLAVE_SRC = secure_enclave_u.c secure_enclave_u.h
 
-sgxwallet_SOURCES = sgxwallet.c SGXWalletServer.cpp SGXRegistrationServer.cpp RPCException.cpp  BLSCrypto.cpp ECDSACrypto.cpp \
+sgxwallet_SOURCES = sgxwallet.c SGXWalletServer.cpp SGXRegistrationServer.cpp CSRManagerServer.cpp RPCException.cpp  BLSCrypto.cpp ECDSACrypto.cpp \
 DKGCrypto.cpp ServerInit.cpp BLSPrivateKeyShareSGX.cpp LevelDB.cpp ServerDataChecker.cpp $(COMMON_SRC)
 
 
@@ -102,7 +102,13 @@ sgxwallet_LDADD=-l$(SGX_URTS_LIB) -LlibBLS/deps/deps_inst/x86_or_x64/lib -Llevel
 
 
 testw_SOURCES=testw.cpp stubclient.cpp SGXWalletServer.cpp  RPCException.cpp BLSCrypto.cpp ServerInit.cpp LevelDB.cpp \
- DKGCrypto.cpp BLSPrivateKeyShareSGX.cpp ECDSACrypto.cpp ServerDataChecker.cpp  SGXRegistrationServer.cpp $(COMMON_SRC)
+ DKGCrypto.cpp BLSPrivateKeyShareSGX.cpp ECDSACrypto.cpp ServerDataChecker.cpp  SGXRegistrationServer.cpp CSRManagerServer.cpp $(COMMON_SRC)
 nodist_testw_SOURCES=${nodist_sgxwallet_SOURCES}
 EXTRA_testw_DEPENDENCIES=${EXTRA_sgxwallet_DEPENDENCIES}
 testw_LDADD= ${sgxwallet_LDADD}
+
+cert_util_SOURCES=cert_util.cpp stubclient.cpp RPCException.cpp LevelDB.cpp SGXRegistrationServer.cpp CSRManagerServer.cpp
+cert_util_LDADD=-LlibBLS/deps/deps_inst/x86_or_x64/lib -Lleveldb/build -LlibBLS/build \
+                   -LlibBLS/build/libff/libff \
+                   -l:libbls.a -l:libleveldb.a \
+                   -l:libff.a -lgmp  -ljsonrpccpp-stub -ljsonrpccpp-server -ljsonrpccpp-client -ljsonrpccpp-common -ljsoncpp -lmicrohttpd -lgnutls -lgcrypt -lcurl -lssl -lcrypto -lz -lpthread -ldl
diff --git a/SGXRegistrationServer.cpp b/SGXRegistrationServer.cpp
index 0f53617..c52c846 100644
--- a/SGXRegistrationServer.cpp
+++ b/SGXRegistrationServer.cpp
@@ -22,8 +22,9 @@
 #include <functional>
 
 #include "SGXRegistrationServer.h"
+#include "LevelDB.h"
 
-SGXRegistrationServer *sr = nullptr;
+SGXRegistrationServer *regs = nullptr;
 HttpServer *hs2 = nullptr;
 
 bool cert_created = false;
@@ -33,49 +34,53 @@ void set_cert_created1(bool b){
   cert_created = b;
 }
 
-
 SGXRegistrationServer::SGXRegistrationServer(AbstractServerConnector &connector,
                                  serverVersion_t type, bool auto_sign)
     : AbstractRegServer(connector, type), is_cert_created(false), cert_auto_sign(auto_sign) {}
 
 
-Json::Value SignSertificateImpl(const std::string& cert, bool auto_sign = false){
+Json::Value SignCertificateImpl(const std::string& csr, bool auto_sign = false){
   Json::Value result;
   result["status"] = 0;
   result["errorMessage"] = "";
   try{
-    //std::hash = cryptlite::sha256::hash_hex(cert);
-
-    std::cerr << " going to create csr" << std::endl;
-
+    std::cerr << " enter SignCertificateImpl " << std::endl;
 
+    std::string status = "1";
+    std::string hash = cryptlite::sha256::hash_hex(csr);
+    if ( !auto_sign) {
+      std::string db_key = "CSR:HASH:" + hash;
+      csrDb->writeDataUnique(db_key, csr);
+    }
 
-  std::ofstream outfile ("cert/client.csr");
-  outfile << cert << std::endl;
-  outfile.close();
-  std::string csrPath = "cert/client.csr";
-  if (access(csrPath.c_str(), F_OK) != 0){
-    throw RPCException(FILE_NOT_FOUND, "Csr does not exist");
-  }
-  result["result"] = true;
-  std::thread thr(set_cert_created1, true);
-  thr.detach();
+    if (auto_sign) {
+      std::string csr_name = "cert/" + hash + ".csr";
+      std::ofstream outfile(csr_name);
+      outfile << csr << std::endl;
+      outfile.close();
+      if (access(csr_name.c_str(), F_OK) != 0) {
+        throw RPCException(FILE_NOT_FOUND, "Csr does not exist");
+      }
 
+      std::string genCert = "cd cert && ./create_client_cert " + hash;
 
+      if (system(genCert.c_str()) == 0){
+          std::cerr << "CLIENT CERTIFICATE IS SUCCESSFULLY GENERATED" << std::endl;
+          status = "0";
+      }
+      else{
+          std::cerr << "CLIENT CERTIFICATE GENERATION FAILED" << std::endl;
+          throw RPCException(FAIL_TO_CREATE_CERTIFICATE, "CLIENT CERTIFICATE GENERATION FAILED");
+          //exit(-1);
+      }
+    }
 
- // std::thread timeout_thr (std::bind(&SGXRegistrationServer::set_cert_created, this, true));
+    result["result"] = true;
+    result["hash"] = hash;
 
-  if (auto_sign) {
-    std::string genCert = "cd cert && ./create_client_cert";
+    std::string db_key = "CSR:HASH:" + hash + "STATUS:";
+    csrStatusDb->writeDataUnique(db_key, status);
 
-        if (system(genCert.c_str()) == 0){
-          std::cerr << "CLIENT CERTIFICATE IS SUCCESSFULLY GENERATED" << std::endl;
-        }
-        else{
-          std::cerr << "CLIENT CERTIFICATE GENERATION FAILED" << std::endl;
-          exit(-1);
-        }
-  }
   } catch (RPCException &_e) {
     std::cerr << " err str " << _e.errString << std::endl;
     result["status"] = _e.status;
@@ -88,31 +93,49 @@ Json::Value SignSertificateImpl(const std::string& cert, bool auto_sign = false)
 
 Json::Value GetSertificateImpl(const std::string& hash){
   Json::Value result;
-  result["status"] = 0;
+  result["status"] = 1;
   result["errorMessage"] = "";
   std::string cert;
   try{
-    if (!cert_created){
-      result["status"] = 1;
-      result["cert"] = "";
-    }
-    else {
-      std::ifstream infile("cert/client.crt");
-      if (!infile.is_open()) {
-        throw RPCException(FILE_NOT_FOUND, "Certificate does not exist");
-      } else {
-        ostringstream ss;
-        ss << infile.rdbuf();
-        cert = ss.str();
-
-        infile.close();
-
-        system("cd cert && rm -rf client.crt");
+//    std::string rejected_name = "rejected_" + hash + ".txt";
+//    if (access(rejected_name.c_str(), F_OK) == 0){
+//      result["status"] = 2;
+//      result["cert"] = "";
+//      return result;
+//    }
 
-        result["cert"] = cert;
-        result["status"] = 0;
+    std::string db_key = "CSR:HASH:" + hash + "STATUS:";
+    std::shared_ptr<string> status_str_ptr = csrStatusDb->readString(db_key);
+    if (status_str_ptr == nullptr){
+       throw RPCException(FILE_NOT_FOUND, "Data with this name does not exist in csr db");
+    }
+    int status = std::atoi(status_str_ptr->c_str());
+
+
+    if ( status == 0){
+      std::string crt_name = "cert/" + hash + ".crt";
+      //if (access(crt_name.c_str(), F_OK) == 0){
+        std::ifstream infile(crt_name);
+        if (!infile.is_open()) {
+          throw RPCException(FILE_NOT_FOUND, "Certificate does not exist");
+        } else {
+          ostringstream ss;
+          ss << infile.rdbuf();
+          cert = ss.str();
+
+          infile.close();
+          std::string remove_crt = "cd cert && rm -rf" + hash + ".crt";
+          system(remove_crt.c_str());
+
+//        result["cert"] = cert;
+//        result["status"] = 0;
       }
     }
+//    else if (access(crt_name.c_str(), F_OK) != 0){
+//      result["status"] = 1;
+//      result["cert"] = "";
+//    }
+
   } catch (RPCException &_e) {
     std::cerr << " err str " << _e.errString << std::endl;
     result["status"] = _e.status;
@@ -124,10 +147,10 @@ Json::Value GetSertificateImpl(const std::string& hash){
 }
 
 
-Json::Value SGXRegistrationServer::SignCertificate(const std::string& cert){
+Json::Value SGXRegistrationServer::SignCertificate(const std::string& csr){
   std::cerr << "Enter SignCertificate " << std::endl;
   lock_guard<recursive_mutex> lock(m);
-  return SignSertificateImpl(cert, cert_auto_sign);
+  return SignCertificateImpl(csr, cert_auto_sign);
 }
 
 Json::Value SGXRegistrationServer::GetCertificate(const std::string& hash){
@@ -161,13 +184,20 @@ int init_registration_server(bool sign_automatically) {
 //    }
 //  }
 
-  hs2 = new HttpServer(1031);
-  sr = new SGXRegistrationServer(*hs2,
+  hs2 = new HttpServer(BASE_PORT + 1);
+  regs = new SGXRegistrationServer(*hs2,
                                  JSONRPC_SERVER_V2, sign_automatically); // hybrid server (json-rpc 1.0 & 2.0)
 
-  if (!sr->StartListening()) {
+  if (!regs->StartListening()) {
     cerr << "Registration server could not start listening" << endl;
     exit(-1);
   }
+  else {
+    cerr << "Registration Server started on port " << BASE_PORT + 1 << endl;
+  }
+
+
+
   return 0;
-}
\ No newline at end of file
+}
+
diff --git a/SGXRegistrationServer.h b/SGXRegistrationServer.h
index 0873adf..c740703 100644
--- a/SGXRegistrationServer.h
+++ b/SGXRegistrationServer.h
@@ -25,7 +25,7 @@ public:
 
   void set_cert_created(bool b);
 
-  virtual Json::Value SignCertificate(const std::string& cert);
+  virtual Json::Value SignCertificate(const std::string& csr);
   virtual Json::Value GetCertificate(const std::string& hash);
 
 };
@@ -34,4 +34,5 @@ public:
 extern int init_registration_server(bool sign_automatically = false);
 
 
+
 #endif // SGXD_SGXREGISTRATIONSERVER_H
\ No newline at end of file
diff --git a/ServerInit.cpp b/ServerInit.cpp
index 9ca8c88..97698f6 100644
--- a/ServerInit.cpp
+++ b/ServerInit.cpp
@@ -46,8 +46,8 @@
 #include "LevelDB.h"
 
 #include "SGXWalletServer.h"
-
 #include "SGXRegistrationServer.h"
+#include "CSRManagerServer.h"
 
 #include "BLSCrypto.h"
 #include "ServerInit.h"
@@ -63,9 +63,13 @@ void init_daemon() {
     libff::init_alt_bn128_params();
 
     static std::string dbName("./" WALLETDB_NAME);
+    levelDb = new LevelDB(dbName);
 
+    static std::string csr_dbname = "CSR_DB";
+    csrDb = new LevelDB(csr_dbname);
 
-    levelDb = new LevelDB(dbName);
+    static std::string csr_status_dbname = "CSR_STATUS_DB";
+    csrStatusDb = new LevelDB(csr_status_dbname);
 
 }
 
@@ -117,8 +121,6 @@ int sgxServerInited = 0;
 
 void init_all(bool check_cert, bool sign_automatically) {
 
-
-
     if (sgxServerInited == 1)
         return;
 
@@ -126,6 +128,7 @@ void init_all(bool check_cert, bool sign_automatically) {
 
     init_server(check_cert);
     init_registration_server(sign_automatically);
+    init_csrmanager_server();
     init_enclave();
     std::cerr << "enclave inited" << std::endl;
     init_daemon();
diff --git a/cert/create_client_cert b/cert/create_client_cert
index c5957b4..88daf47 100755
--- a/cert/create_client_cert
+++ b/cert/create_client_cert
@@ -1,4 +1,8 @@
 #!/bin/bash
 
 #sign csr
-yes | openssl ca -config ca.config -in "client.csr" -out "client.crt"
+CSREXT=".csr"
+CRTEXT=".crt"
+CSRFILE="$1$CSREXT"
+CRTFILE="$1$CRTEXT" 
+yes | openssl ca -config ca.config -in $CSRFILE -out $CRTFILE
diff --git a/cert_util.cpp b/cert_util.cpp
new file mode 100644
index 0000000..d2d1b4f
--- /dev/null
+++ b/cert_util.cpp
@@ -0,0 +1,64 @@
+//
+// Created by kladko on 12/27/19.
+//
+
+#include <iostream>
+#include <cstring>
+#include <jsonrpccpp/client/connectors/httpclient.h>
+#include "stubclient.h"
+
+#include <unistd.h>
+
+int print_hashes(){
+  jsonrpc::HttpClient client("http://localhost:1028");
+  StubClient c(client, jsonrpc::JSONRPC_CLIENT_V2);
+  std::cout << "Client inited" << std::endl;
+  std::cout << c.GetUnsignedCSRs() << std::endl;
+  exit(0);
+}
+
+void sign_by_hash(std::string & hash, int status){
+  jsonrpc::HttpClient client("http://localhost:1028");
+  StubClient c(client, jsonrpc::JSONRPC_CLIENT_V2);
+  std::cout << "Client inited" << std::endl;
+  std::cout << c.SignByHash(hash, status) << std::endl;
+  exit(0);
+}
+
+int main(int argc, char *argv[]) {
+
+  int opt;
+
+  if (argc > 1 && strlen(argv[1]) == 1) {
+    fprintf(stderr, "option is too short %s\n", argv[1]);
+    exit(1);
+  }
+
+  if (argc == 1) {
+    std::cout << "You may use following flags:" << std::endl;
+    std::cout << " -p  print all unsigned csr hashes " << std::endl;
+    std::cout << " -s [hash] sign csr by hash" << std::endl;
+    std::cout << " -r [hash] reject csr by hash" << std::endl;
+    exit(0);
+  }
+     std::string hash;
+      while ((opt = getopt(argc, argv, "ps:r:")) != -1) {
+          switch (opt) {
+
+              case 'p': print_hashes();
+                        break;
+              case 's': hash = optarg;
+                        sign_by_hash(hash, 0);
+                        break;
+              case 'r': hash = optarg;
+                        sign_by_hash(hash, 2);
+                        break;
+              case '?': // fprintf(stderr, "unknown flag\n");
+                        exit(1);
+
+          }
+      }
+
+  return 0;
+}
+
diff --git a/sgxwallet.c b/sgxwallet.c
index a68836f..55d52d1 100644
--- a/sgxwallet.c
+++ b/sgxwallet.c
@@ -61,16 +61,15 @@ int main(int argc, char *argv[]) {
 
   while ((opt = getopt(argc, argv, "csh")) != -1) {
     switch (opt) {
-//    case 'h':
-//      if (strlen(argv[1]) == 2 ) {
-//        fprintf(stderr, "-c  client certificate will not be checked\n");
-//        fprintf(stderr, "-s  client certificate will be signed automatically\n");
-//        exit(0);
-//      } else {
-//        fprintf(stderr, "unknown flag %s\n", argv[1]);
-//        exit(1);
-//      }
-
+    case 'h':
+      if (strlen(argv[1]) == 2 ) {
+        fprintf(stderr, "-c  client certificate will not be checked\n");
+        fprintf(stderr, "-s  client certificate will be signed automatically\n");
+        exit(0);
+      } else {
+        fprintf(stderr, "unknown flag %s\n", argv[1]);
+        exit(1);
+      }
     case 'c':
       check_client_cert = false;
       break;
diff --git a/sgxwallet_common.h b/sgxwallet_common.h
index 6f37ee5..1767359 100644
--- a/sgxwallet_common.h
+++ b/sgxwallet_common.h
@@ -59,7 +59,13 @@
 
 #define FILE_NOT_FOUND -44
 
-#define SGX_ENCLAVE_ERROR -666;
+#define FAIL_TO_CREATE_CERTIFICATE -55
+
+#define SGX_ENCLAVE_ERROR -666
+
+#define MAX_CSR_NUM 1000
+
+#define BASE_PORT 1026
 
 #define WALLETDB_NAME  "sgxwallet.db"//"test_sgxwallet.db"//
 #define ENCLAVE_NAME "secure_enclave.signed.so"
diff --git a/stubclient.h b/stubclient.h
index 2b23db4..0739356 100644
--- a/stubclient.h
+++ b/stubclient.h
@@ -197,6 +197,34 @@ class StubClient : public jsonrpc::Client
             throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
     }
 
+
+    ////CSRManagerServer
+
+  Json::Value GetUnsignedCSRs() throw (jsonrpc::JsonRpcException)
+  {
+    Json::Value p;
+    p = Json::nullValue;
+    Json::Value result = this->CallMethod("GetUnsignedCSRs",p);
+    if (result.isObject())
+      return result;
+    else
+      throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
+  }
+
+
+
+    Json::Value SignByHash(const std::string& hash, int status) throw (jsonrpc::JsonRpcException)
+    {
+        Json::Value p;
+        p["hash"] = hash;
+        p["status"] = status;
+        Json::Value result = this->CallMethod("SignByHash",p);
+        if (result.isObject())
+            return result;
+        else
+            throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
+    }
+
 };
 
 #endif //JSONRPC_CPP_STUB_STUBCLIENT_H_
-- 
2.18.1