Jelajahi Sumber

Merge pull request #13011 from mayx/HPCC-22475-SigningService

HPCC-22475 ESP service to sign ECL code

Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 5 tahun lalu
induk
melakukan
a0fd8d91a4

+ 1 - 0
esp/eclwatch/ws_XSLT/CMakeLists.txt

@@ -175,6 +175,7 @@ FOREACH ( iFILES
     ${CMAKE_CURRENT_SOURCE_DIR}/account.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/account_input.xslt
     ${CMAKE_CURRENT_SOURCE_DIR}/account_myaccount.xslt
+    ${CMAKE_CURRENT_SOURCE_DIR}/codesign.xslt
 )
     Install ( FILES ${iFILES} DESTINATION componentfiles/smc_xslt COMPONENT Runtime )
 ENDFOREACH ( iFILES )

+ 73 - 0
esp/eclwatch/ws_XSLT/codesign.xslt

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
+<xsl:output method="html"/>
+    <xsl:output method="html"/>
+    <xsl:template match="/">
+        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+        <head>
+            <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+            <title>SignResponse</title>
+      <link rel="stylesheet" type="text/css" href="/esp/files/yui/build/fonts/fonts-min.css" />
+      <link rel="stylesheet" type="text/css" href="/esp/files/css/espdefault.css" />
+        </head>
+          <body class="yui-skin-sam" onload="nof5();">
+            <p align="left" />
+            <xsl:apply-templates/>
+          </body>
+        </html>
+      </xsl:template>
+      <xsl:template match="SignResponse">
+          <table>
+            <tr>
+              <th colspan="5">
+                <h3>SignResponse</h3>
+              </th>
+            </tr>
+            <tr>
+              <td>
+                <b>
+                  <xsl:text>RetCode: </xsl:text>
+                </b>
+              </td>
+              <td>
+                <xsl:value-of select="RetCode"/>
+              </td>
+            </tr>
+            <tr>
+              <td>
+                <b>ErrMsg: </b>
+              </td>
+              <td>
+                <xsl:value-of select="ErrMsg"/>
+              </td>
+            </tr>
+            <tr>
+              <td>
+                <b>SignedText: </b>
+              </td>
+          <td>
+        <pre>
+            <xsl:value-of select="SignedText"/>
+        </pre>
+              </td>
+            </tr>
+          </table>
+      </xsl:template>
+</xsl:stylesheet>

+ 1 - 0
esp/scm/espscm.cmake

@@ -43,6 +43,7 @@ set ( ESPSCM_SRCS
       ws_configmgr.ecm
       ws_elk.ecm
       ws_store.ecm
+      ws_codesign.ecm
     )
 
 foreach ( loop_var ${ESPSCM_SRCS} )

+ 1 - 0
esp/scm/smcscm.cmake

@@ -36,6 +36,7 @@ set ( ESPSCM_SRCS
       ws_packageprocess.ecm
       ws_esdlconfig.ecm
       ws_elk.ecm
+      ws_codesign.ecm
     )
 
 foreach ( loop_var ${ESPSCM_SRCS} )

+ 44 - 0
esp/scm/ws_codesign.ecm

@@ -0,0 +1,44 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+ESPenum SigningMethodType : string
+{
+    gpg ("gpg")
+};
+
+ESPrequest SignRequest
+{
+    ESPenum SigningMethodType SigningMethod("gpg");
+    [cols(20)] string KeyIdentifier;
+    [password, cols(20)] string KeyPass;
+    [cols(70), rows(20)] string Text;
+};
+
+ESPresponse [exceptions_inline] SignResponse
+{
+    int RetCode;
+    string ErrMsg;
+    string SignedText;
+};
+
+ESPservice [auth_feature("CodeSignAccess:ACCESS"), version("1.0"), default_client_version("1.0"), exceptions_inline("./smc_xslt/exceptions.xslt")] ws_codesign
+{
+    ESPmethod [auth_feature("CodeSignAccess:FULL"), client_xslt("/esp/xslt/codesign.xslt")] Sign(SignRequest, SignResponse);
+};
+
+SCMexportdef(ws_codesign);
+
+SCMapi(ws_codesign) IClientws_codesign *createws_codesignClient();

+ 1 - 0
esp/services/CMakeLists.txt

@@ -39,3 +39,4 @@ endif()
 HPCC_ADD_SUBDIRECTORY (espcontrol "PLATFORM")
 HPCC_ADD_SUBDIRECTORY (ws_elk "PLATFORM")
 HPCC_ADD_SUBDIRECTORY (ws_store "PLATFORM")
+HPCC_ADD_SUBDIRECTORY (ws_codesign "PLATFORM")

+ 74 - 0
esp/services/ws_codesign/CMakeLists.txt

@@ -0,0 +1,74 @@
+################################################################################
+#    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+################################################################################
+
+
+# Component: ws_codesign
+#####################################################
+# Description:
+# ------------
+#    Cmake Input File for ws_codesign
+#####################################################
+
+project( ws_codesign )
+
+include(${HPCC_SOURCE_DIR}/esp/scm/smcscm.cmake)
+
+set (    SRCS
+         ${HPCC_SOURCE_DIR}/esp/scm/ws_codesign.ecm
+         ${ESPSCM_GENERATED_DIR}/ws_codesign_esp.cpp
+         ./ws_codesignService.cpp
+         ./ws_codesignPlugin.cpp
+    )
+
+include_directories (
+         ${HPCC_SOURCE_DIR}/esp/bindings/http/platform
+         ${HPCC_SOURCE_DIR}/esp/esplib
+         ${HPCC_SOURCE_DIR}/esp/platform
+         ${HPCC_SOURCE_DIR}/system/jlib
+         ${HPCC_SOURCE_DIR}/common/environment
+         ${HPCC_SOURCE_DIR}/esp/services
+         ${HPCC_SOURCE_DIR}/common
+         ${HPCC_SOURCE_DIR}/system/security/securesocket
+         ${HPCC_SOURCE_DIR}/system/security/shared
+         ${HPCC_SOURCE_DIR}/system/include
+         ${HPCC_SOURCE_DIR}/common/remote
+         ${HPCC_SOURCE_DIR}/esp/clients
+         ${HPCC_SOURCE_DIR}/dali/base
+         ${HPCC_SOURCE_DIR}/common/dllserver
+         ${HPCC_SOURCE_DIR}/esp/bindings
+         ${HPCC_SOURCE_DIR}/esp/bindings/SOAP/xpp
+         ${HPCC_SOURCE_DIR}/esp/bindings/http/client
+         ${HPCC_SOURCE_DIR}/esp/http/platform
+         ${HPCC_SOURCE_DIR}/system/mp
+         ${HPCC_SOURCE_DIR}/system/xmllib
+         ${CMAKE_BINARY_DIR}
+         ${CMAKE_BINARY_DIR}/oss
+         ${CMAKE_BINARY_DIR}/esp/services/ws_codesign
+    )
+
+ADD_DEFINITIONS( -D_USRDLL )
+
+HPCC_ADD_LIBRARY( ws_codesign SHARED ${SRCS}  )
+add_dependencies (ws_codesign espscm )
+install ( TARGETS ws_codesign RUNTIME DESTINATION ${EXEC_DIR} LIBRARY DESTINATION ${LIB_DIR} )
+target_link_libraries ( ws_codesign
+         jlib
+         xmllib
+         esphttp
+         dalibase
+         environment
+         SMCLib
+    )

+ 64 - 0
esp/services/ws_codesign/ws_codesignPlugin.cpp

@@ -0,0 +1,64 @@
+
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#pragma warning (disable : 4786)
+
+#ifndef WS_CODESIGN_API
+#define WS_CODESIGN_API DECL_EXPORT
+#endif //WS_CODESIGN_API
+
+#include "ws_codesign_esp.ipp"
+
+//ESP Bindings
+#include "httpprot.hpp"
+
+//ESP Service
+#include "ws_codesignService.hpp"
+
+#include "espplugin.hpp"
+
+extern "C"
+{
+
+ESP_FACTORY IEspService * esp_service_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process)
+{
+    if (strcmp(type, "ws_codesign")==0)
+    {
+        Cws_codesignEx* service = new Cws_codesignEx;
+        service->init(cfg, process, name);
+        return service;
+    }
+    return nullptr;
+}
+
+ESP_FACTORY IEspRpcBinding * esp_binding_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process)
+{
+    if (strcmp(type, "ws_codesignSoapBinding")==0)
+    {
+        return new Cws_codesignSoapBinding(cfg, name, process);
+    }
+
+    return nullptr;
+}
+
+ESP_FACTORY IEspProtocol * esp_protocol_factory(const char *name, const char* type, IPropertyTree *cfg, const char *process)
+{
+    return http_protocol_factory(name, type, cfg, process);
+}
+
+} // extern "C"

+ 110 - 0
esp/services/ws_codesign/ws_codesignService.cpp

@@ -0,0 +1,110 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#include "ws_codesignService.hpp"
+#include "jutil.hpp"
+
+Cws_codesignEx::Cws_codesignEx()
+{
+}
+
+Cws_codesignEx::~Cws_codesignEx()
+{
+}
+
+void Cws_codesignEx::init(IPropertyTree *cfg, const char *process, const char *service)
+{
+    if(cfg == nullptr)
+        throw MakeStringException(-1, "Cannot initialize Cws_codesignEx, cfg is NULL");
+
+    StringBuffer xpath;
+    xpath.appendf("Software/EspProcess[@name=\"%s\"]/EspService[@name=\"%s\"]", process, service);
+    m_serviceCfg.setown(cfg->getPropTree(xpath.str()));
+
+    StringBuffer output, errmsg;
+    int ret = runExternalCommand(output, errmsg, "gpg --version", "");
+    if (ret != 0)
+        throw MakeStringException(-1, "Error running gpg: %s", errmsg.str());
+
+    isGPGv1 = strstr(output.str(), "gpg (GnuPG) 1.");
+}
+
+bool Cws_codesignEx::onSign(IEspContext &context, IEspSignRequest &req, IEspSignResponse &resp)
+{
+    resp.setRetCode(-1);
+
+    StringBuffer keyid(req.getKeyIdentifier());
+    keyid.trim();
+    const char* text = req.getText();
+    if (keyid.length() == 0 || !text || !*text)
+    {
+        resp.setErrMsg("Please provide both KeyIdentifier and Text");
+        return false;
+    }
+    if (strstr(keyid.str(), "\""))
+    {
+        resp.setErrMsg("Invalid KeyIdentifier");
+        return false;
+    }
+
+    StringBuffer cmd, output, errmsg;
+    if (isGPGv1)
+        cmd.appendf("gpg --list-secret-keys \"%s\"", keyid.str());
+    else
+        cmd.appendf("gpg --list-secret-keys --with-keygrip \"%s\"", keyid.str());
+    int ret = runExternalCommand(output, errmsg, cmd.str(), "");
+    if (ret != 0 || strstr(output.str(), keyid.str()) == nullptr)
+    {
+        resp.setErrMsg("Key not found");
+        return false;
+    }
+
+    if (!isGPGv1)
+    {
+        StringBuffer keygrip;
+        auto kgptr = strstr(output.str(), "Keygrip = ");
+        if (kgptr)
+            keygrip.append(40, kgptr+10);
+
+        if (keygrip.length() > 0)
+        {
+            output.clear();
+            errmsg.clear();
+            cmd.clear().appendf("gpg-connect-agent \"clear_passphrase --mode=normal %s\" /bye", keygrip.str());
+            runExternalCommand(output, errmsg, cmd.str(), "");
+        }
+    }
+
+    output.clear();
+    errmsg.clear();
+    cmd.clear().appendf("gpg --clearsign -u \"%s\" --yes --batch --passphrase-fd 0", keyid.str());
+    if (!isGPGv1)
+        cmd.append(" --pinentry-mode loopback");
+    VStringBuffer input("%s\n", req.getKeyPass());
+    input.append(text);
+    ret = runExternalCommand(output, errmsg, cmd.str(), input.str());
+    if (ret != 0 || output.length() == 0)
+    {
+        UERRLOG("gpg clearsign error: [%d] %s\nOutput: n%s", ret, errmsg.str(), output.str());
+        resp.setErrMsg("Failed to sign text, please check service log for details");
+        return false;
+    }
+
+    resp.setRetCode(0);
+    resp.setSignedText(output.str());
+    return true;
+}

+ 37 - 0
esp/services/ws_codesign/ws_codesignService.hpp

@@ -0,0 +1,37 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#ifndef _WS_CODESIGNSERVICE_HPP_
+#define _WS_CODESIGNSERVICE_HPP_
+
+#include "ws_codesign_esp.ipp"
+
+class Cws_codesignEx : public Cws_codesign
+{
+private:
+    Owned<IPropertyTree> m_serviceCfg;
+    bool isGPGv1 = false;
+public:
+    IMPLEMENT_IINTERFACE
+
+    Cws_codesignEx();
+    virtual ~Cws_codesignEx();
+    virtual void init(IPropertyTree *cfg, const char *process, const char *service);
+    virtual bool onSign(IEspContext &context, IEspSignRequest &req, IEspSignResponse &resp);
+};
+
+#endif // _WS_CODESIGNSERVICE_HPP_

+ 35 - 0
initfiles/componentfiles/configxml/@temp/esp_service_WsSMC.xsl

@@ -129,6 +129,10 @@ This is required by its binding with ESP service '<xsl:value-of select="$espServ
             <xsl:with-param name="bindingNode" select="$bindingNode"/>
             <xsl:with-param name="authNode" select="$authNode"/>
         </xsl:apply-templates>
+        <xsl:apply-templates select="." mode="ws_codesign">
+            <xsl:with-param name="bindingNode" select="$bindingNode"/>
+            <xsl:with-param name="authNode" select="$authNode"/>
+        </xsl:apply-templates>
     </xsl:template>
 
     <!-- WS-SMC -->
@@ -675,6 +679,37 @@ This is required by its binding with ESP service '<xsl:value-of select="$espServ
          <xsl:apply-templates select="@*[string(.) != '']|node()" mode="copy"/>
       </xsl:copy>
    </xsl:template>
+
+    <!-- ws_codesign -->
+    <xsl:template match="EspService" mode="ws_codesign">
+        <xsl:param name="bindingNode"/>
+        <xsl:param name="authNode"/>
+
+        <xsl:variable name="serviceType" select="'ws_codesign'"/>
+        <xsl:variable name="serviceName" select="concat($serviceType, '_', @name, '_', $process)"/>
+        <xsl:variable name="bindName" select="concat($serviceType, '_', $bindingNode/@name, '_', $process)"/>
+        <xsl:variable name="bindType" select="'ws_codesignSoapBinding'"/>
+        <xsl:variable name="servicePlugin">
+            <xsl:call-template name="defineServicePlugin">
+                <xsl:with-param name="plugin" select="'ws_codesign'"/>
+            </xsl:call-template>
+        </xsl:variable>
+        <EspService name="{$serviceName}" type="{$serviceType}" plugin="{$servicePlugin}">
+        </EspService>
+        <EspBinding name="{$bindName}" service="{$serviceName}" protocol="{$bindingNode/@protocol}" type="{$bindType}"
+            plugin="{$servicePlugin}" netAddress="0.0.0.0" port="{$bindingNode/@port}">
+            <xsl:call-template name="bindAuthentication">
+                <xsl:with-param name="bindingNode" select="$bindingNode"/>
+                <xsl:with-param name="authMethod" select="$authNode/@method"/>
+                <xsl:with-param name="service" select="'ws_codesign'"/>
+            </xsl:call-template>
+        </EspBinding>
+    </xsl:template>
+   <xsl:template match="*" mode="copy">
+      <xsl:copy>
+         <xsl:apply-templates select="@*[string(.) != '']|node()" mode="copy"/>
+      </xsl:copy>
+   </xsl:template>
    
    <xsl:template match="@*" mode="copy">
       <xsl:if test="string(.) != ''">