You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by bb...@apache.org on 2020/01/07 23:06:47 UTC
[geode-native] branch develop updated: Revert "GEODE-7625: Remove
broken Diffie-Hellman code"
This is an automated email from the ASF dual-hosted git repository.
bbender pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode-native.git
The following commit(s) were added to refs/heads/develop by this push:
new 6b46256 Revert "GEODE-7625: Remove broken Diffie-Hellman code"
6b46256 is described below
commit 6b46256dd03d5406f19c8cb465df03b61a30fb8a
Author: Blake Bender <bb...@pivotal.io>
AuthorDate: Tue Jan 7 15:04:55 2020 -0800
Revert "GEODE-7625: Remove broken Diffie-Hellman code"
This reverts commit de672d7faded5b17c8c22ecabaa6aaf3deab24cb.
- Change somehow (???) broke Ubuntu builds of cryptoimpl library. Looks like something isn't linking in SSL library like it should
- reverting back to known good state for now, since it'll take a little while to investigate breakage
---
CMakeLists.txt | 1 +
clicache/integration-test/test.bat.in | 2 +
cppcache/include/geode/SystemProperties.hpp | 15 +-
cppcache/integration-test/CMakeLists.txt | 4 +-
cppcache/integration-test/test.bat.in | 1 +
cppcache/integration-test/test.sh.in | 1 +
.../integration-test/testThinClientSecurityDH.cpp | 471 ++++++++++++++
.../testThinClientSecurityDH_MU.cpp | 503 +++++++++++++++
cppcache/integration/test/CMakeLists.txt | 2 +-
cppcache/src/DiffieHellman.cpp | 198 ++++++
cppcache/src/DiffieHellman.hpp | 109 ++++
cppcache/src/DistributedSystem.hpp | 1 +
cppcache/src/DistributedSystemImpl.cpp | 5 +-
cppcache/src/DistributedSystemImpl.hpp | 2 +
cppcache/src/SystemProperties.cpp | 6 +-
cppcache/src/TcrConnection.cpp | 144 ++++-
cppcache/src/TcrConnection.hpp | 23 +
cppcache/src/TcrMessage.cpp | 44 +-
cppcache/src/TcrMessage.hpp | 4 +-
cppcache/src/ThinClientBaseDM.cpp | 8 +-
cryptoimpl/CMakeLists.txt | 2 +
cryptoimpl/DHImpl.cpp | 713 +++++++++++++++++++++
cryptoimpl/DHImpl.hpp | 100 +++
{templates/security => dhimpl}/CMakeLists.txt | 21 +-
dhimpl/DHImpl.cpp | 612 ++++++++++++++++++
dhimpl/DHImpl.hpp | 69 ++
.../configuring/sysprops.html.md.erb | 2 +-
.../security/security-systemprops.html.md.erb | 2 +-
.../configuring/sysprops.html.md.erb | 2 +-
.../security/security-systemprops.html.md.erb | 2 +-
templates/security/CMakeLists.txt | 2 +
templates/security/PkcsAuthInit.cpp | 192 ++++++
templates/security/PkcsAuthInit.hpp | 96 +++
tests/cli/CMakeLists.txt | 1 +
tests/cli/NewFwkLib/CacheServer.cs | 53 ++
tests/cli/NewFwkLib/NewFwkLib.csproj.in | 5 +
tests/cli/PkcsWrapper/CMakeLists.txt | 57 ++
tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp | 47 ++
tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp | 65 ++
tests/cli/SecurityUtil/CredentialGeneratorN.cs | 2 +
tests/cli/SecurityUtil/SecurityUtil.csproj.in | 5 +
.../SecurityUtil/XmlAuthzCredentialGeneratorN.cs | 12 +
tests/cpp/security/CMakeLists.txt | 2 +
tests/cpp/security/PkcsAuthInit.cpp | 220 +++++++
tests/cpp/security/PkcsAuthInit.hpp | 100 +++
45 files changed, 3862 insertions(+), 66 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf9c5e4..c1e6b38 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -366,6 +366,7 @@ add_subdirectory(dependencies)
add_subdirectory(openssl-compat)
add_subdirectory(cppcache)
add_subdirectory(cryptoimpl)
+add_subdirectory(dhimpl)
add_subdirectory(sqliteimpl)
add_subdirectory(templates/security)
add_subdirectory(docs/api)
diff --git a/clicache/integration-test/test.bat.in b/clicache/integration-test/test.bat.in
index 87874b1..5c358c4 100644
--- a/clicache/integration-test/test.bat.in
+++ b/clicache/integration-test/test.bat.in
@@ -22,7 +22,9 @@ set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:framework>>;%PATH%
set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:testobject>>;%PATH%
set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:SqLiteImpl>>;%PATH%
set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:cryptoImpl>>;%PATH%
+set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:DHImpl>>;%PATH%
set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:securityImpl>>;%PATH%
+set PATH=$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:PkcsWrapper>>;%PATH%
set PATH=$<JOIN:$<SHELL_PATH:${PATH}>,;>;%PATH%
set PATH=c:\Program Files (x86)\Nunit 2.6.4\bin;%PATH%
diff --git a/cppcache/include/geode/SystemProperties.hpp b/cppcache/include/geode/SystemProperties.hpp
index ab4963e..f00d6aa 100644
--- a/cppcache/include/geode/SystemProperties.hpp
+++ b/cppcache/include/geode/SystemProperties.hpp
@@ -283,12 +283,7 @@ class APACHE_GEODE_EXPORT SystemProperties {
m_onClientDisconnectClearPdxTypeIds = set;
}
- /**
- * @return Empty string
- * @deprecated Diffie-Hellman based credentials encryption is not supported.
- */
- _GEODE_DEPRECATED_(
- "Diffie-Hellman based credentials encryption is not supported.")
+ /** Return the security Diffie-Hellman secret key algorithm */
const std::string& securityClientDhAlgo() const {
return m_securityClientDhAlgo;
}
@@ -313,12 +308,10 @@ class APACHE_GEODE_EXPORT SystemProperties {
}
/**
- * @deprecated Diffie-Hellman based credentials encryption is not supported.
- * @return false.
+ * Check whether Diffie-Hellman based credentials encryption is on.
+ * @return bool flag to indicate whether DH for credentials is on.
*/
- _GEODE_DEPRECATED_(
- "Diffie-Hellman based credentials encryption is not supported.")
- bool isDhOn() const { return false; }
+ bool isDhOn() const { return !m_securityClientDhAlgo.empty(); }
/**
* Whether a non durable client starts to receive and process
diff --git a/cppcache/integration-test/CMakeLists.txt b/cppcache/integration-test/CMakeLists.txt
index dc2d6b5..f231bf8 100644
--- a/cppcache/integration-test/CMakeLists.txt
+++ b/cppcache/integration-test/CMakeLists.txt
@@ -124,7 +124,7 @@ foreach(FILE ${SOURCES})
endif()
# Some tests depend on these library
- add_dependencies(${TEST} securityImpl cryptoImpl SqLiteImpl)
+ add_dependencies(${TEST} securityImpl cryptoImpl DHImpl SqLiteImpl)
add_clangformat(${TEST})
@@ -232,6 +232,8 @@ set_property(TEST testThinClientSecurityAuthentication PROPERTY LABELS OMITTED)
set_property(TEST testThinClientSecurityAuthenticationMU PROPERTY LABELS OMITTED)
set_property(TEST testThinClientSecurityAuthorization PROPERTY LABELS OMITTED)
set_property(TEST testThinClientSecurityAuthorizationMU PROPERTY LABELS OMITTED)
+set_property(TEST testThinClientSecurityDH PROPERTY LABELS OMITTED)
+set_property(TEST testThinClientSecurityDH_MU PROPERTY LABELS OMITTED)
set_property(TEST testThinClientSecurityDurableCQAuthorizationMU PROPERTY LABELS OMITTED)
set_property(TEST testThinClientSecurityPostAuthorization PROPERTY LABELS OMITTED)
set_property(TEST testThinClientTicket303 PROPERTY LABELS OMITTED)
diff --git a/cppcache/integration-test/test.bat.in b/cppcache/integration-test/test.bat.in
index 8bf1f6b..ba99c08 100644
--- a/cppcache/integration-test/test.bat.in
+++ b/cppcache/integration-test/test.bat.in
@@ -22,6 +22,7 @@ set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:framework>>
set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:testobject>>
set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:SqLiteImpl>>
set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:cryptoImpl>>
+set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:DHImpl>>
set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:securityImpl>>
set PATH=%PATH%;$<SHELL_PATH:$<TARGET_LINKER_FILE_DIR:unit_test_callbacks>>
set PATH=%PATH%;$<JOIN:$<SHELL_PATH:${PATH}>,;>
diff --git a/cppcache/integration-test/test.sh.in b/cppcache/integration-test/test.sh.in
index 920cf9b..033d0a1 100644
--- a/cppcache/integration-test/test.sh.in
+++ b/cppcache/integration-test/test.sh.in
@@ -23,6 +23,7 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:framework>
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:testobject>
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:SqLiteImpl>
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:cryptoImpl>
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:DHImpl>
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:securityImpl>
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<TARGET_LINKER_FILE_DIR:unit_test_callbacks>
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$<JOIN:${LD_LIBRARY_PATH},:>
diff --git a/cppcache/integration-test/testThinClientSecurityDH.cpp b/cppcache/integration-test/testThinClientSecurityDH.cpp
new file mode 100644
index 0000000..776f584
--- /dev/null
+++ b/cppcache/integration-test/testThinClientSecurityDH.cpp
@@ -0,0 +1,471 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "fw_dunit.hpp"
+#include "ThinClientHelper.hpp"
+#include <ace/OS.h>
+#include <ace/High_Res_Timer.h>
+
+#include "ThinClientSecurity.hpp"
+
+/* Test Coverage DH Algo
+BF1 - Blowfish:128 , BF2 - Blowfish:448
+AES1- AES:128, AES2- AES:192, AES3- AES:256
+DES- DESede:192
+
+ATTENTION: Blowfish:448, AES:192 and AES:256 needs Unlimited security strength
+policy. For this
+1- Downloaded jce_policy-6.zip from
+http://java.sun.com/javase/downloads/index.jsp.
+2- Unzip and replace 2 jar files in $gfe.dir/jre/lib/security folder.
+ Above mentioned Algo are commented as we can't ship product folder with above
+mentioned Jar files.
+ To test this test fully, please make above changes and uncomment related Algo
+portion in this test.
+*/
+
+#define BF1 "Blowfish:128"
+#define BF2 "Blowfish:448"
+#define AES1 "AES:128"
+#define AES2 "AES:192"
+#define AES3 "AES:256"
+#define DES "DESede"
+
+#define CLIENT1 s1p1
+#define CLIENT2 s1p2
+#define CLIENT3 s2p1
+#define LOCATORSERVER s2p2
+
+#define CORRECT_CREDENTIALS 'C'
+#define INCORRECT_CREDENTIALS 'I'
+
+using apache::geode::client::testframework::security::CredentialGenerator;
+
+const char *locHostPort =
+ CacheHelper::getLocatorHostPort(isLocator, isLocalServer, 1);
+const char *regionNamesAuth[] = {"DistRegionAck", "DistRegionNoAck"};
+std::shared_ptr<CredentialGenerator> credentialGeneratorHandler;
+
+std::string getXmlPath() {
+ char xmlPath[1000] = {'\0'};
+ const char *path = ACE_OS::getenv("TESTSRC");
+ ASSERT(path != nullptr,
+ "Environment variable TESTSRC for test source directory is not set.");
+ strncpy(xmlPath, path, strlen(path) - strlen("cppcache"));
+ strncat(xmlPath, "xml/Security/", sizeof(xmlPath) - strlen(xmlPath) - 1);
+ return std::string(xmlPath);
+}
+
+void initCredentialGenerator() {
+ static int loopNum = 1;
+
+ switch (loopNum) {
+ case 1: {
+ credentialGeneratorHandler = CredentialGenerator::create("DUMMY");
+ LOG("Creating Dummy Credential Generator");
+ break;
+ }
+ case 2: {
+ credentialGeneratorHandler = CredentialGenerator::create("LDAP");
+ LOG("Creating LDAP Credential Generator");
+ break;
+ }
+ default:
+ case 3: {
+ credentialGeneratorHandler = CredentialGenerator::create("PKCS");
+ LOG("Creating PKCS Credential Generator");
+ break;
+ }
+ }
+
+ if (credentialGeneratorHandler == nullptr) {
+ FAIL("credentialGeneratorHandler is nullptr");
+ }
+
+ loopNum++;
+ if (loopNum > 3) loopNum = 1;
+}
+
+void initClientAuth(char credentialsType, const char *dhAlgo) {
+ printf("Initializing Client with %s credential and %s DH Algo\n",
+ credentialsType == CORRECT_CREDENTIALS ? "Valid" : "Invalid", dhAlgo);
+
+ auto config = Properties::create();
+
+ config->insert("security-client-dhalgo", dhAlgo);
+ std::string testsrc = ACE_OS::getenv("TESTSRC");
+ testsrc += "/keystore/geode.pem";
+ printf("KeyStore Path is: %s", testsrc.c_str());
+ config->insert("security-client-kspath", testsrc.c_str());
+
+ if (credentialGeneratorHandler == nullptr) {
+ FAIL("credentialGeneratorHandler is nullptr");
+ }
+ bool insertAuthInit = true;
+ switch (credentialsType) {
+ case CORRECT_CREDENTIALS:
+ credentialGeneratorHandler->getValidCredentials(config);
+ config->insert("security-password",
+ config->find("security-username")->value().c_str());
+ printf("Username is %s and Password is %s ",
+ config->find("security-username")->value().c_str(),
+ config->find("security-password")->value().c_str());
+ break;
+ case INCORRECT_CREDENTIALS:
+ credentialGeneratorHandler->getInvalidCredentials(config);
+ config->insert("security-password", "junk");
+ printf("Username is %s and Password is %s ",
+ config->find("security-username")->value().c_str(),
+ config->find("security-password")->value().c_str());
+ break;
+ default:
+ insertAuthInit = false;
+ break;
+ }
+ if (insertAuthInit) {
+ credentialGeneratorHandler->getAuthInit(config);
+ }
+
+ try {
+ initClient(true, config);
+ } catch (...) {
+ throw;
+ }
+}
+
+void InitIncorrectClients(const char *dhAlgo) {
+ try {
+ initClientAuth(INCORRECT_CREDENTIALS, dhAlgo);
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ }
+
+ try {
+ createRegionForSecurity(regionNamesAuth[0], USE_ACK, true);
+ FAIL("Should have thrown AuthenticationFailedException.");
+ } catch (const apache::geode::client::AuthenticationFailedException &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ FAIL("Only AuthenticationFailedException is expected");
+ }
+ LOG("InitIncorrectClients Completed");
+}
+
+void InitCorrectClients(const char *dhAlgo) {
+ try {
+ initClientAuth(CORRECT_CREDENTIALS, dhAlgo);
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ }
+ try {
+ createRegionForSecurity(regionNamesAuth[0], USE_ACK, true);
+ createEntry(regionNamesAuth[0], keys[0], vals[0]);
+ updateEntry(regionNamesAuth[0], keys[0], nvals[0]);
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ FAIL(other.what());
+ }
+ LOG("Handshake and Authentication successfully completed");
+}
+
+void DoNetSearch() {
+ try {
+ createRegionForSecurity(regionNamesAuth[1], USE_ACK, true);
+ auto regPtr0 = getHelper()->getRegion(regionNamesAuth[0]);
+ auto keyPtr = CacheableKey::create(keys[0]);
+ auto checkPtr =
+ std::dynamic_pointer_cast<CacheableString>(regPtr0->get(keyPtr));
+ if (checkPtr != nullptr && !strcmp(nvals[0], checkPtr->value().c_str())) {
+ LOG("checkPtr is not null");
+ char buf[1024];
+ sprintf(buf, "In net search, get returned %s for key %s",
+ checkPtr->value().c_str(), keys[0]);
+ LOG(buf);
+ } else {
+ LOG("checkPtr is nullptr");
+ }
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ FAIL(other.what());
+ }
+ LOG("Handshake and Authentication successfully completed after FailOver");
+}
+
+void initSecurityServer(int instance) {
+ std::string cmdServerAuthenticator;
+ if (credentialGeneratorHandler == nullptr) {
+ FAIL("credentialGeneratorHandler is nullptr");
+ }
+
+ try {
+ if (isLocalServer) {
+ cmdServerAuthenticator = credentialGeneratorHandler->getServerCmdParams(
+ "authenticator", getXmlPath());
+
+ std::string testsrc = ACE_OS::getenv("TESTSRC");
+ if (instance == 1) {
+ testsrc += "/keystore/geode1.keystore";
+ cmdServerAuthenticator += " security-server-kspath=";
+ cmdServerAuthenticator += testsrc;
+ cmdServerAuthenticator +=
+ " security-server-ksalias=geode1 "
+ "security-server-kspasswd=geode";
+ } else if (instance == 2) {
+ testsrc += "/keystore/geode2.keystore";
+ cmdServerAuthenticator += " security-server-kspath=";
+ cmdServerAuthenticator += testsrc;
+ cmdServerAuthenticator +=
+ " security-server-ksalias=geode2 "
+ "security-server-kspasswd=geode";
+ }
+
+ printf("Input to server cmd is --> %s\n",
+ cmdServerAuthenticator.c_str());
+ CacheHelper::initServer(
+ instance, nullptr, locHostPort,
+ const_cast<char *>(cmdServerAuthenticator.c_str()));
+ }
+ } catch (...) {
+ printf("this is some exception");
+ }
+}
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateLocator)
+ {
+ if (isLocator) CacheHelper::initLocator(1);
+ LOG("Locator1 started");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer1)
+ {
+ initCredentialGenerator();
+ initSecurityServer(1);
+ LOG("Server1 started");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer2)
+ {
+ initSecurityServer(2);
+ LOG("Server2 started");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF1)
+ {
+ initCredentialGenerator();
+ InitIncorrectClients(BF1);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES1)
+ {
+ initCredentialGenerator();
+ InitIncorrectClients(AES1);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectDES)
+ {
+ initCredentialGenerator();
+ InitIncorrectClients(DES);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpCorrectBF1)
+ {
+ InitCorrectClients(BF1);
+ LOG("Client created");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpCorrectAES1)
+ {
+ InitCorrectClients(AES1);
+ LOG("Client created");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpCorrectDES)
+ {
+ InitCorrectClients(DES);
+ LOG("Client created");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF2)
+ {
+ InitIncorrectClients(BF2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES2)
+ {
+ InitIncorrectClients(AES2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectAES3)
+ {
+ InitIncorrectClients(AES3);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownCorrectBF2)
+ {
+ InitCorrectClients(BF2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownCorrectAES2)
+ {
+ InitCorrectClients(AES2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownCorrectAES3)
+ {
+ InitCorrectClients(AES3);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1NetSearch)
+ {
+ SLEEP(1000);
+ DoNetSearch();
+ LOG("StepFive Completed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2NetSearch)
+ {
+ DoNetSearch();
+ LOG("StepFive Completed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3NetSearch)
+ {
+ DoNetSearch();
+ LOG("StepFive Completed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, CloseCache1)
+ { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, CloseCache2)
+ { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, CloseCache3)
+ { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer1)
+ {
+ if (isLocalServer) {
+ CacheHelper::closeServer(1);
+ LOG("SERVER1 stopped");
+ }
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer2)
+ {
+ if (isLocalServer) {
+ CacheHelper::closeServer(2);
+ LOG("SERVER2 stopped");
+ }
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseLocator)
+ {
+ if (isLocator) {
+ CacheHelper::closeLocator(1);
+ LOG("Locator1 stopped");
+ }
+ }
+END_TASK_DEFINITION
+
+void doThinClientSecurityDH() {
+ CALL_TASK(CreateLocator);
+ CALL_TASK(CreateServer1);
+ CALL_TASK(C1UpDownIncorrectBF1);
+ CALL_TASK(C2UpDownIncorrectAES1);
+ CALL_TASK(C3UpDownIncorrectDES);
+ CALL_TASK(C1UpCorrectBF1);
+ CALL_TASK(C2UpCorrectAES1);
+ CALL_TASK(C3UpCorrectDES);
+ CALL_TASK(CreateServer2);
+ CALL_TASK(CloseServer1);
+ CALL_TASK(C1NetSearch);
+ CALL_TASK(C2NetSearch);
+ CALL_TASK(C3NetSearch);
+ CALL_TASK(CloseCache1);
+ CALL_TASK(CloseCache2);
+ CALL_TASK(CloseCache3);
+
+ // Commented for Unlimited Security strength policy : See comment at top of
+ // testThinClientSecurityDH.cpp
+ // CALL_TASK(C1UpDownIncorrectBF2);
+ // CALL_TASK(C2UpDownIncorrectAES2);
+ // CALL_TASK(C3UpDownIncorrectAES3);
+ // CALL_TASK(C1UpDownCorrectBF2);
+ // CALL_TASK(C2UpDownCorrectAES2);
+ // CALL_TASK(C3UpDownCorrectAES3);
+ CALL_TASK(CloseServer2);
+ CALL_TASK(CloseLocator);
+}
+
+DUNIT_MAIN
+ { doThinClientSecurityDH(); }
+END_MAIN
diff --git a/cppcache/integration-test/testThinClientSecurityDH_MU.cpp b/cppcache/integration-test/testThinClientSecurityDH_MU.cpp
new file mode 100644
index 0000000..68a62d0
--- /dev/null
+++ b/cppcache/integration-test/testThinClientSecurityDH_MU.cpp
@@ -0,0 +1,503 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+#define ROOT_NAME "testThinClientSecurityDH_MU"
+
+#include "fw_dunit.hpp"
+#include "ThinClientHelper.hpp"
+#include <ace/OS.h>
+#include <ace/High_Res_Timer.h>
+
+#include "ThinClientSecurity.hpp"
+
+/* Test Coverage DH Algo
+BF1 - Blowfish:128 , BF2 - Blowfish:448
+AES1- AES:128, AES2- AES:192, AES3- AES:256
+DES- DESede:192
+
+ATTENTION: Blowfish:448, AES:192 and AES:256 needs Unlimited security strength
+policy. For this
+1- Downloaded jce_policy-6.zip from
+http://java.sun.com/javase/downloads/index.jsp.
+2- Unzip and replace 2 jar files in $gfe.dir/jre/lib/security folder.
+ Above mentioned Algo are commented as we can't ship product folder with above
+mentioned Jar files.
+ To test this test fully, please make above changes and uncomment related Algo
+portion in this test.
+*/
+
+#define BF1 "Blowfish:128"
+#define BF2 "Blowfish:448"
+#define AES1 "AES:128"
+#define AES2 "AES:192"
+#define AES3 "AES:256"
+#define DES "DESede"
+
+#define CLIENT1 s1p1
+#define CLIENT2 s1p2
+#define CLIENT3 s2p1
+#define LOCATORSERVER s2p2
+
+#define CORRECT_CREDENTIALS 'C'
+#define INCORRECT_CREDENTIALS 'I'
+
+using apache::geode::client::testframework::security::CredentialGenerator;
+
+const char *locHostPort =
+ CacheHelper::getLocatorHostPort(isLocator, isLocalServer, 1);
+const char *regionNamesAuth[] = {"DistRegionAck", "DistRegionNoAck"};
+std::shared_ptr<CredentialGenerator> credentialGeneratorHandler;
+
+std::string getXmlPath() {
+ char xmlPath[1000] = {'\0'};
+ const char *path = ACE_OS::getenv("TESTSRC");
+ ASSERT(path != nullptr,
+ "Environment variable TESTSRC for test source directory is not set.");
+ strncpy(xmlPath, path, strlen(path) - strlen("cppcache"));
+ strncat(xmlPath, "xml/Security/", sizeof(xmlPath) - strlen(xmlPath) - 1);
+ return std::string(xmlPath);
+}
+
+void initCredentialGenerator() {
+ static int loopNum = 1;
+
+ switch (loopNum) {
+ case 1: {
+ credentialGeneratorHandler = CredentialGenerator::create("DUMMY");
+ LOG("Creating Dummy Credential Generator");
+ break;
+ }
+ case 2: {
+ credentialGeneratorHandler = CredentialGenerator::create("LDAP");
+ LOG("Creating LDAP Credential Generator");
+ break;
+ }
+ default:
+ case 3: {
+ credentialGeneratorHandler = CredentialGenerator::create("PKCS");
+ LOG("Creating PKCS Credential Generator");
+ break;
+ }
+ }
+
+ if (credentialGeneratorHandler == nullptr) {
+ FAIL("credentialGeneratorHandler is nullptr");
+ }
+
+ loopNum++;
+ if (loopNum > 2) loopNum = 1;
+}
+
+static std::shared_ptr<Properties> userCreds;
+
+void initClientAuth(char credentialsType, const char *dhAlgo) {
+ printf("Initializing Client with %s credential and %s DH Algo\n",
+ credentialsType == CORRECT_CREDENTIALS ? "Valid" : "Invalid", dhAlgo);
+
+ auto config = Properties::create();
+ userCreds = Properties::create();
+
+ config->insert("security-client-dhalgo", dhAlgo);
+ std::string testsrc = ACE_OS::getenv("TESTSRC");
+ testsrc += "/keystore/geode.pem";
+ printf("KeyStore Path is: %s", testsrc.c_str());
+ config->insert("security-client-kspath", testsrc.c_str());
+
+ if (credentialGeneratorHandler == nullptr) {
+ FAIL("credentialGeneratorHandler is nullptr");
+ }
+ bool insertAuthInit = true;
+ switch (credentialsType) {
+ case CORRECT_CREDENTIALS:
+ credentialGeneratorHandler->getValidCredentials(userCreds);
+ userCreds->insert("security-password",
+ userCreds->find("security-username")->value().c_str());
+ printf("Username is %s and Password is %s ",
+ userCreds->find("security-username")->value().c_str(),
+ userCreds->find("security-password")->value().c_str());
+ break;
+ case INCORRECT_CREDENTIALS:
+ credentialGeneratorHandler->getInvalidCredentials(userCreds);
+ userCreds->insert("security-password", "junk");
+ printf("Username is %s and Password is %s ",
+ userCreds->find("security-username")->value().c_str(),
+ userCreds->find("security-password")->value().c_str());
+ break;
+ default:
+ insertAuthInit = false;
+ break;
+ }
+ if (insertAuthInit) {
+ // credentialGeneratorHandler->getAuthInit(config);
+ }
+
+ try {
+ initClient(true, config);
+ } catch (...) {
+ throw;
+ }
+}
+
+void InitIncorrectClients(const char *dhAlgo) {
+ try {
+ initClientAuth(INCORRECT_CREDENTIALS, dhAlgo);
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ }
+
+ try {
+ createRegionForSecurity(regionNamesAuth[0], USE_ACK, false, nullptr, false,
+ -1, true, 0);
+ auto pool = getPool(regionNamesAuth[0]);
+ LOG(" 6");
+ if (pool != nullptr) {
+ LOG(" 7");
+ auto virtualCache = getVirtualCache(userCreds, pool);
+ LOG(" 8");
+ virtualCache.getRegion(regionNamesAuth[0])->put(keys[0], vals[0]);
+ LOG("Operation allowed, something is wrong.");
+ }
+ FAIL("Should have thrown AuthenticationFailedException.");
+ } catch (const apache::geode::client::AuthenticationFailedException &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ FAIL("Only AuthenticationFailedException is expected");
+ }
+ LOG("InitIncorrectClients Completed");
+}
+
+void InitCorrectClients(const char *dhAlgo) {
+ try {
+ initClientAuth(CORRECT_CREDENTIALS, dhAlgo);
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ LOG(other.what());
+ }
+ try {
+ createRegionForSecurity(regionNamesAuth[0], USE_ACK, false, nullptr, false,
+ -1, true, 0);
+ auto pool = getPool(regionNamesAuth[0]);
+ LOG(" 6");
+
+ LOG(" 7");
+ auto virtualCache = getVirtualCache(userCreds, pool);
+ LOG(" 8");
+ auto regionPtr = virtualCache.getRegion(regionNamesAuth[0]);
+
+ for (int i = 0; i < 100; i++) regionPtr->put(keys[0], vals[0]);
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ FAIL(other.what());
+ }
+ LOG("Handshake and Authentication successfully completed");
+}
+
+void DoNetSearch() {
+ try {
+ createRegionForSecurity(regionNamesAuth[1], USE_ACK, false, nullptr, false,
+ -1, true, 0);
+ auto pool = getPool(regionNamesAuth[1]);
+ LOG(" 6");
+
+ LOG(" 7");
+ auto virtualCache = getVirtualCache(userCreds, pool);
+ LOG(" 8");
+ auto regionPtr = virtualCache.getRegion(regionNamesAuth[1]);
+
+ auto keyPtr = CacheableKey::create(keys[0]);
+ auto checkPtr =
+ std::dynamic_pointer_cast<CacheableString>(regionPtr->get(keyPtr));
+ if (checkPtr != nullptr && !strcmp(vals[0], checkPtr->value().c_str())) {
+ LOG("checkPtr is not null");
+ char buf[1024];
+ sprintf(buf, "In net search, get returned %s for key %s",
+ checkPtr->value().c_str(), keys[0]);
+ LOG(buf);
+ } else {
+ LOG("checkPtr is nullptr");
+ }
+ } catch (const apache::geode::client::Exception &other) {
+ LOG(other.getStackTrace());
+ FAIL(other.what());
+ }
+ LOG("Handshake and Authentication successfully completed after FailOver");
+}
+
+void initSecurityServer(int instance) {
+ std::string cmdServerAuthenticator;
+ if (credentialGeneratorHandler == nullptr) {
+ FAIL("credentialGeneratorHandler is nullptr");
+ }
+
+ try {
+ if (isLocalServer) {
+ cmdServerAuthenticator = credentialGeneratorHandler->getServerCmdParams(
+ "authenticator", getXmlPath());
+
+ std::string testsrc = ACE_OS::getenv("TESTSRC");
+ if (instance == 1) {
+ testsrc += "/keystore/geode1.keystore";
+ cmdServerAuthenticator += " security-server-kspath=";
+ cmdServerAuthenticator += testsrc;
+ cmdServerAuthenticator +=
+ " security-server-ksalias=geode1 "
+ "security-server-kspasswd=geode";
+ } else if (instance == 2) {
+ testsrc += "/keystore/geode2.keystore";
+ cmdServerAuthenticator += " security-server-kspath=";
+ cmdServerAuthenticator += testsrc;
+ cmdServerAuthenticator +=
+ " security-server-ksalias=geode2 "
+ "security-server-kspasswd=geode";
+ }
+
+ printf("Input to server cmd is --> %s\n",
+ cmdServerAuthenticator.c_str());
+ CacheHelper::initServer(
+ instance, nullptr, locHostPort,
+ const_cast<char *>(cmdServerAuthenticator.c_str()));
+ }
+ } catch (...) {
+ printf("this is some exception");
+ }
+}
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateLocator)
+ {
+ if (isLocator) CacheHelper::initLocator(1);
+ LOG("Locator1 started");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer1)
+ {
+ initCredentialGenerator();
+ initSecurityServer(1);
+ LOG("Server1 started");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CreateServer2)
+ {
+ initSecurityServer(2);
+ LOG("Server2 started");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF1)
+ {
+ initCredentialGenerator();
+ InitIncorrectClients(BF1);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES1)
+ {
+ initCredentialGenerator();
+ InitIncorrectClients(AES1);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectDES)
+ {
+ initCredentialGenerator();
+ InitIncorrectClients(DES);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpCorrectBF1)
+ {
+ InitCorrectClients(BF1);
+ LOG("Client created");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpCorrectAES1)
+ {
+ InitCorrectClients(AES1);
+ LOG("Client created");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpCorrectDES)
+ {
+ InitCorrectClients(DES);
+ LOG("Client created");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownIncorrectBF2)
+ {
+ InitIncorrectClients(BF2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownIncorrectAES2)
+ {
+ InitIncorrectClients(AES2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownIncorrectAES3)
+ {
+ InitIncorrectClients(AES3);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1UpDownCorrectBF2)
+ {
+ InitCorrectClients(BF2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2UpDownCorrectAES2)
+ {
+ InitCorrectClients(AES2);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3UpDownCorrectAES3)
+ {
+ InitCorrectClients(AES3);
+ LOG("Client created");
+ cleanProc();
+ LOG("Client closed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, C1NetSearch)
+ {
+ SLEEP(1000);
+ DoNetSearch();
+ LOG("StepFive Completed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, C2NetSearch)
+ {
+ DoNetSearch();
+ LOG("StepFive Completed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, C3NetSearch)
+ {
+ DoNetSearch();
+ LOG("StepFive Completed");
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT1, CloseCache1)
+ { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT2, CloseCache2)
+ { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(CLIENT3, CloseCache3)
+ { cleanProc(); }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer1)
+ {
+ if (isLocalServer) {
+ CacheHelper::closeServer(1);
+ LOG("SERVER1 stopped");
+ }
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseServer2)
+ {
+ if (isLocalServer) {
+ CacheHelper::closeServer(2);
+ LOG("SERVER2 stopped");
+ }
+ }
+END_TASK_DEFINITION
+
+DUNIT_TASK_DEFINITION(LOCATORSERVER, CloseLocator)
+ {
+ if (isLocator) {
+ CacheHelper::closeLocator(1);
+ LOG("Locator1 stopped");
+ }
+ }
+END_TASK_DEFINITION
+
+void doThinClientSecurityDH() {
+ CALL_TASK(CreateLocator);
+ CALL_TASK(CreateServer1);
+ CALL_TASK(C1UpDownIncorrectBF1);
+ CALL_TASK(C2UpDownIncorrectAES1);
+ CALL_TASK(C3UpDownIncorrectDES);
+ CALL_TASK(C1UpCorrectBF1);
+ CALL_TASK(C2UpCorrectAES1);
+ CALL_TASK(C3UpCorrectDES);
+ CALL_TASK(CreateServer2);
+ CALL_TASK(CloseServer1);
+ CALL_TASK(C1NetSearch);
+ CALL_TASK(C2NetSearch);
+ CALL_TASK(C3NetSearch);
+ CALL_TASK(CloseCache1);
+ CALL_TASK(CloseCache2);
+ CALL_TASK(CloseCache3);
+
+ // Commented for Unlimited Security strength policy : See comment at top of
+ // testThinClientSecurityDH.cpp
+ // CALL_TASK(C1UpDownIncorrectBF2);
+ // CALL_TASK(C2UpDownIncorrectAES2);
+ // CALL_TASK(C3UpDownIncorrectAES3);
+ // CALL_TASK(C1UpDownCorrectBF2);
+ // CALL_TASK(C2UpDownCorrectAES2);
+ // CALL_TASK(C3UpDownCorrectAES3);
+ CALL_TASK(CloseServer2);
+ CALL_TASK(CloseLocator);
+}
+
+DUNIT_MAIN
+ { doThinClientSecurityDH(); }
+END_MAIN
diff --git a/cppcache/integration/test/CMakeLists.txt b/cppcache/integration/test/CMakeLists.txt
index 4c583ed..f76aab8 100644
--- a/cppcache/integration/test/CMakeLists.txt
+++ b/cppcache/integration/test/CMakeLists.txt
@@ -72,7 +72,7 @@ target_link_libraries(cpp-integration-test
internal
)
-add_dependencies(cpp-integration-test cryptoImpl)
+add_dependencies(cpp-integration-test cryptoImpl DHImpl)
if(WIN32)
target_compile_definitions(cpp-integration-test
diff --git a/cppcache/src/DiffieHellman.cpp b/cppcache/src/DiffieHellman.cpp
new file mode 100644
index 0000000..fc0c81d
--- /dev/null
+++ b/cppcache/src/DiffieHellman.cpp
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "DiffieHellman.hpp"
+
+#include <ace/Guard_T.h>
+
+#include <geode/ExceptionTypes.hpp>
+#include <geode/SystemProperties.hpp>
+
+#include "util/Log.hpp"
+namespace apache {
+namespace geode {
+namespace client {
+
+ACE_DLL DiffieHellman::m_dll;
+
+#define INIT_DH_FUNC_PTR(OrigName) \
+ DiffieHellman::OrigName##_Type DiffieHellman::OrigName##_Ptr = nullptr;
+
+INIT_DH_FUNC_PTR(gf_initDhKeys)
+INIT_DH_FUNC_PTR(gf_clearDhKeys)
+INIT_DH_FUNC_PTR(gf_getPublicKey)
+INIT_DH_FUNC_PTR(gf_setPublicKeyOther)
+INIT_DH_FUNC_PTR(gf_computeSharedSecret)
+INIT_DH_FUNC_PTR(gf_encryptDH)
+INIT_DH_FUNC_PTR(gf_decryptDH)
+INIT_DH_FUNC_PTR(gf_verifyDH)
+
+void* DiffieHellman::getOpenSSLFuncPtr(const char* function_name) {
+ void* func = m_dll.symbol(function_name);
+ if (func == nullptr) {
+ char msg[1000];
+ std::snprintf(msg, 1000, "cannot find function %s in library %s",
+ function_name, "cryptoImpl");
+ LOGERROR(msg);
+ throw IllegalStateException(msg);
+ }
+ return func;
+}
+
+void DiffieHellman::initOpenSSLFuncPtrs() {
+ static bool inited = false;
+
+ if (inited) {
+ return;
+ }
+
+ const char* libName = "cryptoImpl";
+
+ if (m_dll.open(libName, ACE_DEFAULT_SHLIB_MODE, 0) == -1) {
+ char msg[1000];
+ std::snprintf(msg, 1000, "cannot open library: %s", libName);
+ LOGERROR(msg);
+ throw FileNotFoundException(msg);
+ }
+
+#define ASSIGN_DH_FUNC_PTR(OrigName) \
+ OrigName##_Ptr = (OrigName##_Type)getOpenSSLFuncPtr(#OrigName);
+
+ ASSIGN_DH_FUNC_PTR(gf_initDhKeys)
+ ASSIGN_DH_FUNC_PTR(gf_clearDhKeys)
+ ASSIGN_DH_FUNC_PTR(gf_getPublicKey)
+ ASSIGN_DH_FUNC_PTR(gf_setPublicKeyOther)
+ ASSIGN_DH_FUNC_PTR(gf_computeSharedSecret)
+ ASSIGN_DH_FUNC_PTR(gf_encryptDH)
+ ASSIGN_DH_FUNC_PTR(gf_decryptDH)
+ ASSIGN_DH_FUNC_PTR(gf_verifyDH)
+
+ inited = true;
+}
+
+void DiffieHellman::initDhKeys(const std::shared_ptr<Properties>& props) {
+ m_dhCtx = nullptr;
+
+ const auto& dhAlgo = props->find(SecurityClientDhAlgo);
+ const auto& ksPath = props->find(SecurityClientKsPath);
+
+ // Null check only for DH Algo
+ if (dhAlgo == nullptr) {
+ LOGFINE("DH algo not available");
+ return;
+ }
+
+ int error =
+ gf_initDhKeys_Ptr(&m_dhCtx, dhAlgo->value().c_str(),
+ ksPath != nullptr ? ksPath->value().c_str() : nullptr);
+
+ if (error == DH_ERR_UNSUPPORTED_ALGO) { // Unsupported Algorithm
+ char msg[64] = {'\0'};
+ std::snprintf(msg, 64, "Algorithm %s is not supported.",
+ dhAlgo->value().c_str());
+ throw IllegalArgumentException(msg);
+ } else if (error == DH_ERR_ILLEGAL_KEYSIZE) { // Illegal Key size
+ char msg[64] = {'\0'};
+ std::snprintf(msg, 64, "Illegal key size for algorithm %s.",
+ dhAlgo->value().c_str());
+ throw IllegalArgumentException(msg);
+ } else if (m_dhCtx == nullptr) {
+ throw IllegalStateException(
+ "Could not initialize the Diffie-Hellman helper");
+ }
+}
+
+void DiffieHellman::clearDhKeys(void) {
+ // Sanity check for accidental calls
+ if (gf_clearDhKeys_Ptr == nullptr) {
+ return;
+ }
+
+ gf_clearDhKeys_Ptr(m_dhCtx);
+
+ m_dhCtx = nullptr;
+
+ return;
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::getPublicKey(void) {
+ int keyLen = 0;
+ auto pubKeyPtr = gf_getPublicKey_Ptr(m_dhCtx, &keyLen);
+ return CacheableBytes::create(
+ std::vector<int8_t>(pubKeyPtr, pubKeyPtr + keyLen));
+}
+
+void DiffieHellman::setPublicKeyOther(
+ const std::shared_ptr<CacheableBytes>& pubkey) {
+ return gf_setPublicKeyOther_Ptr(
+ m_dhCtx, reinterpret_cast<const uint8_t*>(pubkey->value().data()),
+ pubkey->length());
+}
+
+void DiffieHellman::computeSharedSecret(void) {
+ return gf_computeSharedSecret_Ptr(m_dhCtx);
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::encrypt(
+ const std::shared_ptr<CacheableBytes>& cleartext) {
+ return encrypt(reinterpret_cast<const uint8_t*>(cleartext->value().data()),
+ cleartext->length());
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::encrypt(const uint8_t* cleartext,
+ int len) {
+ int cipherLen = 0;
+ auto ciphertextPtr = gf_encryptDH_Ptr(m_dhCtx, cleartext, len, &cipherLen);
+ return CacheableBytes::create(
+ std::vector<int8_t>(ciphertextPtr, ciphertextPtr + cipherLen));
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::decrypt(
+ const std::shared_ptr<CacheableBytes>& cleartext) {
+ return decrypt(reinterpret_cast<const uint8_t*>(cleartext->value().data()),
+ cleartext->length());
+}
+std::shared_ptr<CacheableBytes> DiffieHellman::decrypt(const uint8_t* cleartext,
+ int len) {
+ int cipherLen = 0;
+ auto ciphertextPtr = gf_decryptDH_Ptr(m_dhCtx, cleartext, len, &cipherLen);
+ return CacheableBytes::create(
+ std::vector<int8_t>(ciphertextPtr, ciphertextPtr + cipherLen));
+}
+
+bool DiffieHellman::verify(const std::shared_ptr<CacheableString>& subject,
+ const std::shared_ptr<CacheableBytes>& challenge,
+ const std::shared_ptr<CacheableBytes>& response) {
+ int errCode = DH_ERR_NO_ERROR;
+ LOGDEBUG("DiffieHellman::verify");
+ bool result = gf_verifyDH_Ptr(
+ m_dhCtx, subject->value().c_str(),
+ reinterpret_cast<const uint8_t*>(challenge->value().data()),
+ challenge->length(),
+ reinterpret_cast<const uint8_t*>(response->value().data()),
+ response->length(), &errCode);
+ LOGDEBUG("DiffieHellman::verify 2");
+ if (errCode == DH_ERR_SUBJECT_NOT_FOUND) {
+ LOGERROR("Subject name %s not found in imported certificates.",
+ subject->value().c_str());
+ } else if (errCode == DH_ERR_NO_CERTIFICATES) {
+ LOGERROR("No imported certificates.");
+ } else if (errCode == DH_ERR_INVALID_SIGN) {
+ LOGERROR("Signature varification failed.");
+ }
+
+ return result;
+}
+} // namespace client
+} // namespace geode
+} // namespace apache
diff --git a/cppcache/src/DiffieHellman.hpp b/cppcache/src/DiffieHellman.hpp
new file mode 100644
index 0000000..234cac9
--- /dev/null
+++ b/cppcache/src/DiffieHellman.hpp
@@ -0,0 +1,109 @@
+#pragma once
+
+#ifndef GEODE_DIFFIEHELLMAN_H_
+#define GEODE_DIFFIEHELLMAN_H_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 <string>
+
+#include <ace/DLL.h>
+
+#include <geode/CacheableBuiltins.hpp>
+#include <geode/Properties.hpp>
+
+#define DH_ERR_NO_ERROR 0
+#define DH_ERR_UNSUPPORTED_ALGO 1
+#define DH_ERR_ILLEGAL_KEYSIZE 2
+#define DH_ERR_SUBJECT_NOT_FOUND 3
+#define DH_ERR_NO_CERTIFICATES 4
+#define DH_ERR_INVALID_SIGN 5
+
+const char SecurityClientDhAlgo[] = "security-client-dhalgo";
+const char SecurityClientKsPath[] = "security-client-kspath";
+
+namespace apache {
+namespace geode {
+namespace client {
+
+class DiffieHellman {
+ public:
+ void initDhKeys(const std::shared_ptr<Properties>& props);
+ void clearDhKeys(void);
+ std::shared_ptr<CacheableBytes> getPublicKey(void);
+ void setPublicKeyOther(const std::shared_ptr<CacheableBytes>& pubkey);
+ void computeSharedSecret(void);
+ std::shared_ptr<CacheableBytes> encrypt(
+ const std::shared_ptr<CacheableBytes>& cleartext);
+ std::shared_ptr<CacheableBytes> encrypt(const uint8_t* cleartext, int len);
+ std::shared_ptr<CacheableBytes> decrypt(
+ const std::shared_ptr<CacheableBytes>& cleartext);
+ std::shared_ptr<CacheableBytes> decrypt(const uint8_t* cleartext, int len);
+ bool verify(const std::shared_ptr<CacheableString>& subject,
+ const std::shared_ptr<CacheableBytes>& challenge,
+ const std::shared_ptr<CacheableBytes>& response);
+
+ static void initOpenSSLFuncPtrs();
+
+ DiffieHellman() : m_dhCtx(nullptr) {}
+
+ private:
+ void* m_dhCtx;
+ static void* getOpenSSLFuncPtr(const char* function_name);
+
+ // OpenSSL Func Ptrs: Declare Func Ptr type and a static variable of
+ // std::shared_ptr<Func> type. Convention: <Orig Func Name>_Type and <Orig
+ // Func Name>_Ptr
+ typedef int (*gf_initDhKeys_Type)(void** dhCtx, const char* dhAlgo,
+ const char* ksPath);
+ typedef void (*gf_clearDhKeys_Type)(void* dhCtx);
+ typedef unsigned char* (*gf_getPublicKey_Type)(void* dhCtx, int* len);
+ typedef void (*gf_setPublicKeyOther_Type)(void* dhCtx,
+ const unsigned char* pubkey,
+ int length);
+ typedef void (*gf_computeSharedSecret_Type)(void* dhCtx);
+ typedef unsigned char* (*gf_encryptDH_Type)(void* dhCtx,
+ const unsigned char* cleartext,
+ int len, int* retLen);
+ typedef unsigned char* (*gf_decryptDH_Type)(void* dhCtx,
+ const unsigned char* cleartext,
+ int len, int* retLen);
+ typedef bool (*gf_verifyDH_Type)(void* dhCtx, const char* subject,
+ const unsigned char* challenge,
+ int challengeLen,
+ const unsigned char* response,
+ int responseLen, int* reason);
+
+#define DECLARE_DH_FUNC_PTR(OrigName) static OrigName##_Type OrigName##_Ptr;
+
+ DECLARE_DH_FUNC_PTR(gf_initDhKeys)
+ DECLARE_DH_FUNC_PTR(gf_clearDhKeys)
+ DECLARE_DH_FUNC_PTR(gf_getPublicKey)
+ DECLARE_DH_FUNC_PTR(gf_setPublicKeyOther)
+ DECLARE_DH_FUNC_PTR(gf_computeSharedSecret)
+ DECLARE_DH_FUNC_PTR(gf_encryptDH)
+ DECLARE_DH_FUNC_PTR(gf_decryptDH)
+ DECLARE_DH_FUNC_PTR(gf_verifyDH)
+
+ static ACE_DLL m_dll;
+
+}; // class DiffieHellman
+} // namespace client
+} // namespace geode
+} // namespace apache
+
+#endif // GEODE_DIFFIEHELLMAN_H_
diff --git a/cppcache/src/DistributedSystem.hpp b/cppcache/src/DistributedSystem.hpp
index a03ea6c..f3ba16f 100644
--- a/cppcache/src/DistributedSystem.hpp
+++ b/cppcache/src/DistributedSystem.hpp
@@ -48,6 +48,7 @@ namespace client {
class SystemProperties;
class DistributedSystemImpl;
class CacheRegionHelper;
+class DiffieHellman;
class TcrConnection;
class APACHE_GEODE_EXPORT DistributedSystem {
diff --git a/cppcache/src/DistributedSystemImpl.cpp b/cppcache/src/DistributedSystemImpl.cpp
index 2e20823..a648232 100644
--- a/cppcache/src/DistributedSystemImpl.cpp
+++ b/cppcache/src/DistributedSystemImpl.cpp
@@ -51,6 +51,9 @@ DistributedSystemImpl::DistributedSystemImpl(
m_implementee(implementee),
m_sysProps(std::move(sysProps)),
m_connected(false) {
+ if (!m_sysProps->securityClientDhAlgo().empty()) {
+ DiffieHellman::initOpenSSLFuncPtrs();
+ }
logSystemInformation();
}
@@ -59,7 +62,7 @@ DistributedSystemImpl::~DistributedSystemImpl() {
}
void DistributedSystemImpl::connect() {
- if (m_connected) {
+ if (m_connected == true) {
throw AlreadyConnectedException(
"DistributedSystem::connect: already connected, call getInstance to "
"get it");
diff --git a/cppcache/src/DistributedSystemImpl.hpp b/cppcache/src/DistributedSystemImpl.hpp
index 457c9ea..ff3e2cc 100644
--- a/cppcache/src/DistributedSystemImpl.hpp
+++ b/cppcache/src/DistributedSystemImpl.hpp
@@ -27,6 +27,7 @@
#include <geode/internal/geode_globals.hpp>
+#include "DiffieHellman.hpp"
#include "DistributedSystem.hpp"
#include "statistics/StatisticsManager.hpp"
@@ -67,6 +68,7 @@ class APACHE_GEODE_EXPORT DistributedSystemImpl {
std::string m_name;
DistributedSystem* m_implementee;
+ DiffieHellman m_dh;
/**
* @brief constructors
diff --git a/cppcache/src/SystemProperties.cpp b/cppcache/src/SystemProperties.cpp
index 9e86b01..bc69dc9 100644
--- a/cppcache/src/SystemProperties.cpp
+++ b/cppcache/src/SystemProperties.cpp
@@ -268,8 +268,7 @@ void SystemProperties::processProperty(const std::string& property,
m_securityPropertiesPtr->insert(property, value);
if (property == SecurityClientDhAlgo) {
- throw IllegalArgumentException(
- "Diffie-Hellman based credentials encryption is not supported.");
+ m_securityClientDhAlgo = value;
} else if (property == SecurityClientKsPath) {
m_securityClientKsPath = value;
}
@@ -455,6 +454,9 @@ void SystemProperties::logSettings() {
settings += "\n redundancy-monitor-interval = ";
settings += to_string(redundancyMonitorInterval());
+ settings += "\n security-client-dhalgo = ";
+ settings += securityClientDhAlgo();
+
settings += "\n security-client-kspath = ";
settings += securityClientKsPath();
diff --git a/cppcache/src/TcrConnection.cpp b/cppcache/src/TcrConnection.cpp
index 51e5c09..d23d5d9 100644
--- a/cppcache/src/TcrConnection.cpp
+++ b/cppcache/src/TcrConnection.cpp
@@ -27,6 +27,7 @@
#include "ClientProxyMembershipID.hpp"
#include "Connector.hpp"
+#include "DiffieHellman.hpp"
#include "DistributedSystemImpl.hpp"
#include "TcpSslConn.hpp"
#include "TcrConnectionManager.hpp"
@@ -46,10 +47,10 @@ const int8_t LAST_CHUNK_MASK = 0x1;
const int64_t INITIAL_CONNECTION_ID = 26739;
#define throwException(ex) \
- do { \
+ { \
LOGFINEST(ex.getName() + ": " + ex.getMessage()); \
throw ex; \
- } while (0)
+ }
struct FinalizeProcessChunk {
private:
@@ -78,6 +79,7 @@ bool TcrConnection::initTcrConnection(
// m_connected = isConnected;
m_hasServerQueue = NON_REDUNDANT_SERVER;
m_queueSize = 0;
+ m_dh = nullptr;
// m_chunksProcessSema = 0;
m_creationTime = clock::now();
connectionId = INITIAL_CONNECTION_ID;
@@ -190,6 +192,7 @@ bool TcrConnection::initTcrConnection(
}
handShakeMsg.writeInt(static_cast<int32_t>(1));
+ bool isDhOn = false;
bool requireServerAuth = false;
std::shared_ptr<Properties> credentials;
std::shared_ptr<CacheableBytes> serverChallenge;
@@ -198,18 +201,29 @@ bool TcrConnection::initTcrConnection(
handShakeMsg.write(getOverrides(&sysProp));
bool tmpIsSecurityOn = nullptr != cacheImpl->getAuthInitialize();
+ isDhOn = sysProp.isDhOn();
if (m_endpointObj) {
- tmpIsSecurityOn = tmpIsSecurityOn || m_endpointObj->isMultiUserMode();
+ tmpIsSecurityOn = tmpIsSecurityOn || this->m_endpointObj->isMultiUserMode();
+ auto dhalgo =
+ sysProp.getSecurityProperties()->find("security-client-dhalgo");
+
+ LOGDEBUG("TcrConnection this->m_endpointObj->isMultiUserMode() = %d ",
+ this->m_endpointObj->isMultiUserMode());
+ if (this->m_endpointObj->isMultiUserMode()) {
+ if (dhalgo != nullptr && dhalgo->length() > 0) isDhOn = true;
+ }
}
LOGDEBUG(
- "TcrConnection tmpIsSecurityOn = %d isNotificationChannel = "
- "%d ",
- tmpIsSecurityOn, isNotificationChannel);
+ "TcrConnection algo name %s tmpIsSecurityOn = %d isDhOn = %d "
+ "isNotificationChannel = %d ",
+ sysProp.securityClientDhAlgo().c_str(), tmpIsSecurityOn, isDhOn,
+ isNotificationChannel);
bool doIneedToSendCreds = true;
if (isNotificationChannel && m_endpointObj &&
this->m_endpointObj->isMultiUserMode()) {
+ isDhOn = false;
tmpIsSecurityOn = false;
doIneedToSendCreds = false;
}
@@ -217,6 +231,10 @@ bool TcrConnection::initTcrConnection(
if (isNotificationChannel && !doIneedToSendCreds) {
handShakeMsg.write(
static_cast<uint8_t>(SECURITY_MULTIUSER_NOTIFICATIONCHANNEL));
+ } else if (isDhOn) {
+ m_dh = new DiffieHellman();
+ m_dh->initDhKeys(sysProp.getSecurityProperties());
+ handShakeMsg.write(static_cast<uint8_t>(SECURITY_CREDENTIALS_DHENCRYPT));
} else if (tmpIsSecurityOn) {
handShakeMsg.write(static_cast<uint8_t>(SECURITY_CREDENTIALS_NORMAL));
} else {
@@ -243,9 +261,38 @@ bool TcrConnection::initTcrConnection(
credentials = tmpAuthIniSecurityProperties;
}
}
- if (isClientNotification) {
- credentials->toData(handShakeMsg);
- }
+
+ if (isDhOn) {
+ auto ksPath = tmpSecurityProperties->find("security-client-kspath");
+ requireServerAuth = (ksPath != nullptr && ksPath->length() > 0);
+ handShakeMsg.writeBoolean(requireServerAuth);
+ LOGFINE(
+ "HandShake: Server authentication using RSA signature %s required",
+ requireServerAuth ? "is" : "not");
+
+ // Send the symmetric key algorithm name string
+ handShakeMsg.writeString(sysProp.securityClientDhAlgo());
+
+ // Send the client's DH public key to the server
+ auto dhPubKey = m_dh->getPublicKey();
+ LOGDEBUG("DH pubkey send len is %d", dhPubKey->length());
+ dhPubKey->toData(handShakeMsg);
+
+ if (requireServerAuth) {
+ char serverChallengeBytes[64] = {0};
+ RandGen getrand;
+ for (int pos = 0; pos < 64; pos++) {
+ serverChallengeBytes[pos] = getrand(255);
+ }
+ serverChallenge = CacheableBytes::create(std::vector<int8_t>(
+ serverChallengeBytes, serverChallengeBytes + 64));
+ serverChallenge->toData(handShakeMsg);
+ }
+ } else { // if isDhOn
+ if (isClientNotification) { //:only for backward connection
+ credentials->toData(handShakeMsg);
+ }
+ } // else isDhOn
} catch (const AuthenticationRequiredException&) {
LOGDEBUG("AuthenticationRequiredException got");
throw;
@@ -283,6 +330,77 @@ bool TcrConnection::initTcrConnection(
throwException(ex);
}
+ // if diffie-hellman based credential encryption is enabled
+ if (isDhOn && acceptanceCode[0] == REPLY_OK) {
+ // read the server's DH public key
+ auto pubKeyBytes = readHandshakeByteArray(connectTimeout);
+ LOGDEBUG(" Handshake: Got pubKeySize %d", pubKeyBytes->length());
+
+ // set the server's public key on client's DH side
+ // DiffieHellman::setPublicKeyOther(pubKeyBytes);
+ m_dh->setPublicKeyOther(pubKeyBytes);
+
+ // Note: SK Algo is set in DistributedSystem::connect()
+ // DiffieHellman::computeSharedSecret();
+ m_dh->computeSharedSecret();
+
+ if (requireServerAuth) {
+ // Read Subject Name
+ auto subjectName = readHandshakeString(connectTimeout);
+ LOGDEBUG("Got subject %s", subjectName->value().c_str());
+ // read the server's signature bytes
+ auto responseBytes = readHandshakeByteArray(connectTimeout);
+ LOGDEBUG("Handshake: Got response size %d", responseBytes->length());
+ LOGDEBUG("Handshake: Got serverChallenge size %d",
+ serverChallenge->length());
+ if (!m_dh->verify(subjectName, serverChallenge, responseBytes)) {
+ throwException(AuthenticationFailedException(
+ "Handshake: failed to verify server challenge response"));
+ }
+ LOGFINE("HandShake: Verified server challenge response");
+ }
+
+ // read the challenge bytes from the server
+ auto challengeBytes = readHandshakeByteArray(connectTimeout);
+ LOGDEBUG("Handshake: Got challengeSize %d", challengeBytes->length());
+
+ // encrypt the credentials and challenge bytes
+ auto cleartext = cacheImpl->createDataOutput();
+ if (isClientNotification) { //:only for backward connection
+ credentials->toData(cleartext);
+ }
+ challengeBytes->toData(cleartext);
+ auto ciphertext = m_dh->encrypt(
+ cleartext.getBuffer(), static_cast<int>(cleartext.getBufferLength()));
+
+ auto sendCreds = cacheImpl->createDataOutput();
+ ciphertext->toData(sendCreds);
+ size_t credLength;
+ auto credData = reinterpret_cast<char*>(
+ const_cast<uint8_t*>(sendCreds.getBuffer(&credLength)));
+ // send the encrypted bytes and check the response
+ error = sendData(credData, credLength, connectTimeout, false);
+
+ if (error == CONN_NOERR) {
+ acceptanceCode = readHandshakeData(1, connectTimeout);
+ LOGDEBUG("Handshake: Got acceptanceCode Finally %d", acceptanceCode[0]);
+ } else {
+ int32_t lastError = ACE_OS::last_error();
+ LOGERROR("Handshake failed, errno: %d, server may not be running",
+ lastError);
+ GF_SAFE_DELETE_CON(m_conn);
+ if (error & CONN_TIMEOUT) {
+ throwException(TimeoutException(
+ "TcrConnection::TcrConnection: "
+ "connection timed out during diffie-hellman handshake"));
+ } else {
+ throwException(
+ GeodeIOException("TcrConnection::TcrConnection: "
+ "Handshake failure during diffie-hellman"));
+ }
+ }
+ }
+
auto serverQueueStatus = readHandshakeData(1, connectTimeout);
// TESTING: Durable clients - set server queue status.
@@ -567,10 +685,9 @@ char* TcrConnection::sendRequest(const char* buffer, size_t len,
send(timeSpent, buffer, len, sendTimeoutSec);
- if (timeSpent >= receiveTimeoutSec) {
+ if (timeSpent >= receiveTimeoutSec)
throwException(
TimeoutException("TcrConnection::send: connection timed out"));
- }
receiveTimeoutSec -= timeSpent;
ConnErrType opErr = CONN_NOERR;
@@ -1283,6 +1400,11 @@ TcrConnection::~TcrConnection() {
m_conn->close();
GF_SAFE_DELETE_CON(m_conn);
}
+
+ if (m_dh != nullptr) {
+ m_dh->clearDhKeys();
+ _GEODE_SAFE_DELETE(m_dh);
+ }
}
bool TcrConnection::setAndGetBeingUsed(volatile bool isBeingUsed,
diff --git a/cppcache/src/TcrConnection.hpp b/cppcache/src/TcrConnection.hpp
index 18969e1..c3d09cf 100644
--- a/cppcache/src/TcrConnection.hpp
+++ b/cppcache/src/TcrConnection.hpp
@@ -30,6 +30,7 @@
#include <geode/internal/geode_globals.hpp>
#include "Connector.hpp"
+#include "DiffieHellman.hpp"
#include "TcrMessage.hpp"
#include "util/synchronized_set.hpp"
@@ -40,6 +41,7 @@
#define UNSUCCESSFUL_SERVER_TO_CLIENT 106
#define CLIENT_TO_SERVER 100
#define REPLY_OK 59
+#define REPLY_OK_CS43 58
#define REPLY_REFUSED 60
#define REPLY_INVALID 61
#define REPLY_SSL_ENABLED 21
@@ -49,6 +51,7 @@
#define SECURITY_CREDENTIALS_NONE 0
#define SECURITY_CREDENTIALS_NORMAL 1
+#define SECURITY_CREDENTIALS_DHENCRYPT 2
#define SECURITY_MULTIUSER_NOTIFICATIONCHANNEL 3
/** Closes and Deletes connection only if it exists */
@@ -132,6 +135,7 @@ class APACHE_GEODE_EXPORT TcrConnection {
volatile const bool& isConnected)
: connectionId(0),
m_connectionManager(&connectionManager),
+ m_dh(nullptr),
m_endpoint(nullptr),
m_endpointObj(nullptr),
m_connected(isConnected),
@@ -304,9 +308,28 @@ class APACHE_GEODE_EXPORT TcrConnection {
return *m_connectionManager;
}
+ std::shared_ptr<CacheableBytes> encryptBytes(
+ std::shared_ptr<CacheableBytes> data) {
+ if (m_dh != nullptr) {
+ return m_dh->encrypt(data);
+ } else {
+ return data;
+ }
+ }
+
+ std::shared_ptr<CacheableBytes> decryptBytes(
+ std::shared_ptr<CacheableBytes> data) {
+ if (m_dh != nullptr) {
+ return m_dh->decrypt(data);
+ } else {
+ return data;
+ }
+ }
+
private:
int64_t connectionId;
const TcrConnectionManager* m_connectionManager;
+ DiffieHellman* m_dh;
std::chrono::microseconds calculateHeaderTimeout(
std::chrono::microseconds receiveTimeout, bool retry);
diff --git a/cppcache/src/TcrMessage.cpp b/cppcache/src/TcrMessage.cpp
index aa8361d..aeb3917 100644
--- a/cppcache/src/TcrMessage.cpp
+++ b/cppcache/src/TcrMessage.cpp
@@ -604,11 +604,11 @@ void TcrMessage::readUniqueIDObjectPart(DataInput& input) {
}
}
-int64_t TcrMessage::getConnectionId() {
- if (m_connectionIDBytes) {
+int64_t TcrMessage::getConnectionId(TcrConnection* conn) {
+ if (m_connectionIDBytes != nullptr) {
+ auto tmp = conn->decryptBytes(m_connectionIDBytes);
auto di = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
- reinterpret_cast<const uint8_t*>(m_connectionIDBytes->value().data()),
- m_connectionIDBytes->length());
+ reinterpret_cast<const uint8_t*>(tmp->value().data()), tmp->length());
return di.readInt64();
} else {
LOGWARN("Returning 0 as internal connection ID msgtype = %d ", m_msgType);
@@ -616,12 +616,14 @@ int64_t TcrMessage::getConnectionId() {
}
}
-int64_t TcrMessage::getUniqueId() {
- if (auto cacheableBytes =
- std::dynamic_pointer_cast<CacheableBytes>(m_value)) {
+int64_t TcrMessage::getUniqueId(TcrConnection* conn) {
+ if (m_value != nullptr) {
+ auto encryptBytes = std::dynamic_pointer_cast<CacheableBytes>(m_value);
+
+ auto tmp = conn->decryptBytes(encryptBytes);
+
auto di = m_tcdm->getConnectionManager().getCacheImpl()->createDataInput(
- reinterpret_cast<const uint8_t*>(cacheableBytes->value().data()),
- cacheableBytes->length());
+ reinterpret_cast<const uint8_t*>(tmp->value().data()), tmp->length());
return di.readInt64();
}
return 0;
@@ -2785,7 +2787,7 @@ TcrMessageRemoveUserAuth::TcrMessageRemoveUserAuth(
.c_str());
}
-void TcrMessage::createUserCredentialMessage(TcrConnection*) {
+void TcrMessage::createUserCredentialMessage(TcrConnection* conn) {
m_request->reset();
m_isSecurityHeaderAdded = false;
writeHeader(m_msgType, 1);
@@ -2797,7 +2799,8 @@ void TcrMessage::createUserCredentialMessage(TcrConnection*) {
auto credBytes = CacheableBytes::create(std::vector<int8_t>(
dOut.getBuffer(), dOut.getBuffer() + dOut.getBufferLength()));
- writeObjectPart(credBytes);
+ auto encryptBytes = conn->encryptBytes(credBytes);
+ writeObjectPart(encryptBytes);
writeMessageLength();
LOGDEBUG("TcrMessage::createUserCredentialMessage msg = %s ",
@@ -2828,18 +2831,21 @@ void TcrMessage::addSecurityPart(int64_t connectionId, int64_t unique_id,
auto bytes = CacheableBytes::create(std::vector<int8_t>(
dOutput.getBuffer(), dOutput.getBuffer() + dOutput.getBufferLength()));
+ auto encryptBytes = conn->encryptBytes(bytes);
+
LOGDEBUG("TcrMessage::addSecurityPart [%p] length = %" PRId32
", encrypted ID = %s ",
- conn, bytes->length(),
- Utils::convertBytesToString(bytes->value().data(), bytes->length())
+ conn, encryptBytes->length(),
+ Utils::convertBytesToString(encryptBytes->value().data(),
+ encryptBytes->length())
.c_str());
- writeObjectPart(bytes);
+ writeObjectPart(encryptBytes);
writeMessageLength();
- m_securityHeaderLength = 4 + 1 + bytes->length();
+ m_securityHeaderLength = 4 + 1 + encryptBytes->length();
}
-void TcrMessage::addSecurityPart(int64_t connectionId, TcrConnection*) {
+void TcrMessage::addSecurityPart(int64_t connectionId, TcrConnection* conn) {
LOGDEBUG("TcrMessage::addSecurityPart m_isSecurityHeaderAdded = %d ",
m_isSecurityHeaderAdded);
if (m_isSecurityHeaderAdded) {
@@ -2859,9 +2865,11 @@ void TcrMessage::addSecurityPart(int64_t connectionId, TcrConnection*) {
auto bytes = CacheableBytes::create(std::vector<int8_t>(
dOutput.getBuffer(), dOutput.getBuffer() + dOutput.getBufferLength()));
- writeObjectPart(bytes);
+ auto encryptBytes = conn->encryptBytes(bytes);
+
+ writeObjectPart(encryptBytes);
writeMessageLength();
- m_securityHeaderLength = 4 + 1 + bytes->length();
+ m_securityHeaderLength = 4 + 1 + encryptBytes->length();
LOGDEBUG("TcrMessage addspCC = %s ",
Utils::convertBytesToString(m_request->getBuffer(),
m_request->getBufferLength())
diff --git a/cppcache/src/TcrMessage.hpp b/cppcache/src/TcrMessage.hpp
index 007dbd1..89d4870 100644
--- a/cppcache/src/TcrMessage.hpp
+++ b/cppcache/src/TcrMessage.hpp
@@ -302,9 +302,9 @@ class TcrMessage {
void addSecurityPart(int64_t connectionId, TcrConnection* conn);
- int64_t getConnectionId();
+ int64_t getConnectionId(TcrConnection* conn);
- int64_t getUniqueId();
+ int64_t getUniqueId(TcrConnection* conn);
void createUserCredentialMessage(TcrConnection* conn);
diff --git a/cppcache/src/ThinClientBaseDM.cpp b/cppcache/src/ThinClientBaseDM.cpp
index 82bcea0..a1d741a 100644
--- a/cppcache/src/ThinClientBaseDM.cpp
+++ b/cppcache/src/ThinClientBaseDM.cpp
@@ -300,17 +300,17 @@ void ThinClientBaseDM::afterSendingRequest(const TcrMessage& request,
if (TcrMessage::RESPONSE == reply.getMessageType()) {
if (this->isMultiUserMode()) {
UserAttributes::threadLocalUserAttributes->setConnectionAttributes(
- conn->getEndpointObject(), reply.getUniqueId());
+ conn->getEndpointObject(), reply.getUniqueId(conn));
} else {
- conn->getEndpointObject()->setUniqueId(reply.getUniqueId());
+ conn->getEndpointObject()->setUniqueId(reply.getUniqueId(conn));
}
}
- conn->setConnectionId(reply.getConnectionId());
+ conn->setConnectionId(reply.getConnectionId(conn));
} else if (TcrMessage::isUserInitiativeOps(request)) {
// bugfix: if noack op then reuse previous security token.
conn->setConnectionId(reply.getMessageType() == TcrMessage::INVALID
? conn->getConnectionId()
- : reply.getConnectionId());
+ : reply.getConnectionId(conn));
}
}
}
diff --git a/cryptoimpl/CMakeLists.txt b/cryptoimpl/CMakeLists.txt
index 3852e2b..22a3856 100644
--- a/cryptoimpl/CMakeLists.txt
+++ b/cryptoimpl/CMakeLists.txt
@@ -17,6 +17,8 @@ project(cryptoImpl LANGUAGES CXX)
add_library(cryptoImpl SHARED
${CMAKE_CURRENT_BINARY_DIR}/cryptoimpl_export.h
+ DHImpl.hpp
+ DHImpl.cpp
Ssl.hpp
SSLImpl.hpp
SSLImpl.cpp
diff --git a/cryptoimpl/DHImpl.cpp b/cryptoimpl/DHImpl.cpp
new file mode 100644
index 0000000..1365d32
--- /dev/null
+++ b/cryptoimpl/DHImpl.cpp
@@ -0,0 +1,713 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "DHImpl.hpp"
+
+#include <openssl-compat.h>
+#include <openssl/aes.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include <cctype>
+#include <cstring>
+#include <memory>
+
+/*
+static DH * m_dh = nullptr;
+static string m_skAlgo;
+static int m_keySize = 0;
+static BIGNUM * m_pubKeyOther = nullptr;
+static unsigned char m_key[128] = {0};
+static std::vector<X509*> m_serverCerts;
+*/
+
+static const char *dhP =
+ "13528702063991073999718992897071702177131142188276542919088770094024269"
+ "73079899070080419278066109785292538223079165925365098181867673946"
+ "34756714063947534092593553024224277712367371302394452615862654308"
+ "11180902979719649450105660478776364198726078338308557022096810447"
+ "3500348898008043285865193451061481841186553";
+
+static const char *dhG =
+ "13058345680719715096166513407513969537624553636623932169016704425008150"
+ "56576152779768716554354314319087014857769741104157332735258102835"
+ "93126577393912282416840649805564834470583437473176415335737232689"
+ "81480201869671811010996732593655666464627559582258861254878896534"
+ "1273697569202082715873518528062345259949959";
+
+static const int dhL = 1023;
+
+static int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey);
+static EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key);
+/*
+static const EVP_CIPHER* getCipherFunc();
+static int setSkAlgo(const char * skalgo);
+*/
+
+ASN1_SEQUENCE(
+ DH_PUBKEY) = {ASN1_SIMPLE(DH_PUBKEY, algor, X509_ALGOR),
+ ASN1_SIMPLE(DH_PUBKEY, public_key,
+ ASN1_BIT_STRING)} ASN1_SEQUENCE_END(DH_PUBKEY)
+
+ // This gives us the i2d/d2i x.509 (ASN1 DER) encode/decode functions
+ IMPLEMENT_ASN1_FUNCTIONS(DH_PUBKEY)
+
+ // Returns Error code
+ int gf_initDhKeys(void **dhCtx, const char *dhAlgo, const char *ksPath) {
+ int errorCode = DH_ERR_NO_ERROR; // No error;
+
+ auto dhimpl = new DHImpl();
+ *dhCtx = dhimpl;
+
+ // ksPath can be null
+ if (dhimpl->m_dh || !dhAlgo || strlen(dhAlgo) == 0) {
+ return errorCode;
+ }
+
+ // set the symmetric cipher algorithm name
+ errorCode = dhimpl->setSkAlgo(dhAlgo);
+ if (errorCode != DH_ERR_NO_ERROR) {
+ return errorCode;
+ }
+
+ // do add-all here or outside in DS::connect?
+ if (!DHImpl::m_init) {
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+ DHImpl::m_init = true;
+ }
+
+ dhimpl->m_dh = DH_new();
+
+ BIGNUM *pbn = nullptr;
+ BIGNUM *gbn = nullptr;
+ DH_get0_pqg(dhimpl->m_dh, const_cast<const BIGNUM **>(&pbn), nullptr,
+ const_cast<const BIGNUM **>(&gbn));
+ BN_dec2bn(&pbn, dhP);
+
+ LOGDH(" DHInit: P ptr is %p", pbn);
+ LOGDH(" DHInit: G ptr is %p", gbn);
+ LOGDH(" DHInit: length is %d", DH_get_length(dhimpl->m_dh));
+
+ BN_dec2bn(&gbn, dhG);
+
+ DH_set_length(dhimpl->m_dh, dhL);
+
+ DH_generate_key(dhimpl->m_dh);
+
+ const BIGNUM *pub_key, *priv_key;
+ DH_get0_key(dhimpl->m_dh, &pub_key, &priv_key);
+ BN_num_bits(priv_key);
+
+ BN_num_bits(pub_key);
+
+ int codes = 0;
+ DH_check(dhimpl->m_dh, &codes);
+ LOGDH(" DHInit: DH_check codes is 0x%04X", codes);
+ LOGDH(" DHInit: DH_size is %d", DH_size(dhimpl->m_dh));
+
+ // load the server's RSA public key for server authentication
+ // note that OpenSSL 0.9.8g has a bug where it can read only the first one in
+ // the keystore
+
+ LOGDH(" Loading keystore...");
+
+ if (ksPath == nullptr || strlen(ksPath) == 0) {
+ LOGDH("Property \"security-client-kspath\" 's value is nullptr.");
+ return errorCode;
+ }
+ FILE *keyStoreFP = nullptr;
+ keyStoreFP = fopen(ksPath, "r");
+
+ LOGDH(" kspath is [%s]", ksPath);
+ LOGDH(" keystore FILE ptr is %p", keyStoreFP);
+
+ // Read from pem file and put into.
+ X509 *cert = nullptr;
+ do {
+ cert = PEM_read_X509(keyStoreFP, nullptr, nullptr, nullptr);
+
+ if (cert != nullptr) {
+ dhimpl->m_serverCerts.push_back(cert);
+ }
+ } while (cert != nullptr);
+
+ LOGDH(" Total certificats imported # %zd", dhimpl->m_serverCerts.size());
+
+ fclose(keyStoreFP);
+
+ return errorCode;
+}
+
+void gf_clearDhKeys(void *dhCtx) {
+ DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+ if (dhimpl->m_dh != nullptr) {
+ DH_free(dhimpl->m_dh);
+ dhimpl->m_dh = nullptr;
+ }
+
+ std::vector<X509 *>::const_iterator iter;
+ for (iter = dhimpl->m_serverCerts.begin();
+ iter != dhimpl->m_serverCerts.end(); ++iter) {
+ X509_free(*iter);
+ }
+
+ dhimpl->m_serverCerts.clear();
+
+ if (dhimpl->m_pubKeyOther != nullptr) {
+ BN_free(dhimpl->m_pubKeyOther);
+ dhimpl->m_pubKeyOther = nullptr;
+ }
+
+ memset(dhimpl->m_key, 0, 128);
+
+ // EVP_cleanup();
+}
+
+unsigned char *gf_getPublicKey(void *dhCtx, int *pLen) {
+ DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+ const BIGNUM *pub_key, *priv_key;
+ DH_get0_key(dhimpl->m_dh, &pub_key, &priv_key);
+
+ if (pub_key == nullptr || pLen == nullptr) {
+ return nullptr;
+ }
+
+ int numBytes = BN_num_bytes(pub_key);
+
+ if (numBytes <= 0) {
+ return nullptr;
+ }
+
+ EVP_PKEY *evppubkey = EVP_PKEY_new();
+ LOGDH(" before assign DH ptr is %p\n", dhimpl->m_dh);
+ EVP_PKEY_assign_DH(evppubkey, dhimpl->m_dh);
+ LOGDH(" after assign DH ptr is %p\n", dhimpl->m_dh);
+ DH_PUBKEY *dhpubkey = nullptr;
+ DH_PUBKEY_set(&dhpubkey, evppubkey);
+ int len = i2d_DH_PUBKEY(dhpubkey, nullptr);
+ unsigned char *pubkey = new unsigned char[len];
+ unsigned char *temp = pubkey;
+ //
+ // Note, this temp pointer is needed because OpenSSL increments the pointer
+ // passed in
+ // so that following encoding can be done at the current output location, this
+ // will cause a
+ // problem if we try to free the pointer which has been moved by OpenSSL.
+ //
+ i2d_DH_PUBKEY(dhpubkey, &temp);
+
+ // TODO: uncomment this - causing problem in computeSecret?
+ // DH_PUBKEY_free(dhpubkey);
+ // EVP_PKEY_free(evppubkey);
+
+ LOGDH(" after evp free DH ptr is %p\n", dhimpl->m_dh);
+ *pLen = len;
+ return pubkey;
+}
+
+void gf_setPublicKeyOther(void *dhCtx, const unsigned char *pubkey,
+ int length) {
+ DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+ if (dhimpl->m_pubKeyOther != nullptr) {
+ BN_free(dhimpl->m_pubKeyOther);
+ dhimpl->m_pubKeyOther = nullptr;
+ }
+
+ const unsigned char *temp = pubkey;
+ DH_PUBKEY *dhpubkey = d2i_DH_PUBKEY(nullptr, &temp, length);
+ LOGDH(" setPubKeyOther: after d2i_dhpubkey ptr is %p\n", dhpubkey);
+ EVP_PKEY *evppkey = DH_PUBKEY_get(dhpubkey);
+ LOGDH(" setPubKeyOther: after dhpubkey get evp ptr is %p\n", evppkey);
+ LOGDH(" setPubKeyOther: before BNdup ptr is %p\n", dhimpl->m_pubKeyOther);
+
+ const BIGNUM *pub_key, *priv_key;
+ DH *dh = EVP_PKEY_get1_DH(evppkey);
+ DH_get0_key(dh, &pub_key, &priv_key);
+ dhimpl->m_pubKeyOther = BN_dup(pub_key);
+ LOGDH(" setPubKeyOther: after BNdup ptr is %p\n", dhimpl->m_pubKeyOther);
+ EVP_PKEY_free(evppkey);
+ DH_PUBKEY_free(dhpubkey);
+
+ int codes = 0;
+ DH_check_pub_key(dhimpl->m_dh, dhimpl->m_pubKeyOther, &codes);
+ LOGDH(" DHInit: DH check_pub_key codes is 0x%04X\n", codes);
+}
+
+void gf_computeSharedSecret(void *dhCtx) {
+ DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+ LOGDH("COMPUTE: DH ptr %p, pubkeyOther ptr %p", dhimpl->m_dh,
+ dhimpl->m_pubKeyOther);
+
+ LOGDH("DHcomputeKey DHSize is %d", DH_size(dhimpl->m_dh));
+ DH_compute_key(dhimpl->m_key, dhimpl->m_pubKeyOther, dhimpl->m_dh);
+ LOGDH("DHcomputeKey : Compute err(%d): %s", ERR_get_error(),
+ ERR_error_string(ERR_get_error(), nullptr));
+}
+
+int DHImpl::setSkAlgo(const char *skalgo) {
+ int errCode = DH_ERR_NO_ERROR;
+
+ std::string inAlgo(skalgo);
+ size_t colIdx = inAlgo.find(':');
+ std::string algoStr =
+ (colIdx == std::string::npos) ? inAlgo : inAlgo.substr(0, colIdx);
+ int keySize = 0;
+
+ // Convert input algo to lower case to support case insensitivity
+ for (unsigned int i = 0; i < algoStr.size(); i++) {
+ algoStr[i] = tolower(algoStr[i]);
+ }
+
+ if (algoStr == "aes") {
+ keySize = (colIdx == std::string::npos)
+ ? 128
+ : atoi(inAlgo.substr(colIdx + 1).c_str());
+ if (keySize == 128 || keySize == 192 || keySize == 256) {
+ m_skAlgo = "AES";
+ m_keySize = keySize;
+ } else {
+ return DH_ERR_ILLEGAL_KEYSIZE;
+ }
+ } else if (algoStr == "blowfish") {
+ keySize = (colIdx == std::string::npos)
+ ? 128
+ : atoi(inAlgo.substr(colIdx + 1).c_str());
+ if (keySize >= 128 && keySize <= 448) {
+ m_skAlgo = "Blowfish";
+ m_keySize = keySize;
+ } else {
+ return DH_ERR_ILLEGAL_KEYSIZE;
+ }
+ } else if (algoStr == "desede") { // No keysize should be given
+ if (colIdx == std::string::npos) {
+ m_skAlgo = "DESede";
+ m_keySize = 192;
+ } else {
+ return DH_ERR_ILLEGAL_KEYSIZE;
+ }
+ } else {
+ return DH_ERR_UNSUPPORTED_ALGO;
+ }
+
+ LOGDH(" DH: Got SK algo as %s", m_skAlgo.c_str());
+ LOGDH(" DH: Got keySize as %d", m_keySize);
+
+ return errCode;
+}
+
+const EVP_CIPHER *DHImpl::getCipherFunc() {
+ if (m_skAlgo == "AES") {
+ if (m_keySize == 192) {
+ return EVP_aes_192_cbc();
+ } else if (m_keySize == 256) {
+ return EVP_aes_256_cbc();
+ } else { // Default
+ return EVP_aes_128_cbc();
+ }
+ } else if (m_skAlgo == "Blowfish") {
+ return EVP_bf_cbc();
+ } else if (m_skAlgo == "DESede") {
+ return EVP_des_ede3_cbc();
+ } else {
+ LOGDH("ERROR: Unsupported DH Algorithm");
+ return nullptr;
+ }
+}
+
+unsigned char *gf_encryptDH(void *dhCtx, const unsigned char *cleartext,
+ int len, int *retLen) {
+ DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+ // Validation
+ if (cleartext == nullptr || len < 1 || retLen == nullptr) {
+ return nullptr;
+ }
+
+ LOGDH(" DH: gf_encryptDH using sk algo: %s, Keysize: %d",
+ dhimpl->m_skAlgo.c_str(), dhimpl->m_keySize);
+
+ auto ciphertext = std::unique_ptr<unsigned char[]>(
+ new unsigned char[len + 50]); // give enough room for padding
+ int outlen, tmplen;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+
+ const EVP_CIPHER *cipherFunc = dhimpl->getCipherFunc();
+
+ // init openssl cipher context
+ if (dhimpl->m_skAlgo == "AES") {
+ int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+ EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+ dhimpl->m_key + keySize);
+ } else if (dhimpl->m_skAlgo == "Blowfish") {
+ int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+ EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, nullptr,
+ dhimpl->m_key + keySize);
+ EVP_CIPHER_CTX_set_key_length(ctx, keySize);
+ LOGDH("DHencrypt: BF keysize is %d", keySize);
+ EVP_EncryptInit_ex(ctx, nullptr, nullptr, dhimpl->m_key, nullptr);
+ } else if (dhimpl->m_skAlgo == "DESede") {
+ EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+ dhimpl->m_key + 24);
+ }
+
+ if (!EVP_EncryptUpdate(ctx, ciphertext.get(), &outlen, cleartext, len)) {
+ LOGDH(" DHencrypt: enc update ret nullptr");
+ return nullptr;
+ }
+ /* Buffer passed to EVP_EncryptFinal() must be after data just
+ * encrypted to avoid overwriting it.
+ */
+ tmplen = 0;
+
+ if (!EVP_EncryptFinal_ex(ctx, ciphertext.get() + outlen, &tmplen)) {
+ LOGDH("DHencrypt: enc final ret nullptr");
+ return nullptr;
+ }
+
+ outlen += tmplen;
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ LOGDH("DHencrypt: in len is %d, out len is %d", len, outlen);
+
+ *retLen = outlen;
+ return ciphertext.release();
+}
+
+unsigned char *gf_decryptDH(void *dhCtx, const unsigned char *cleartext,
+ int len, int *retLen) {
+ DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+ // Validation
+ if (cleartext == nullptr || len < 1 || retLen == nullptr) {
+ return nullptr;
+ }
+
+ LOGDH(" DH: gf_encryptDH using sk algo: %s, Keysize: %d",
+ dhimpl->m_skAlgo.c_str(), dhimpl->m_keySize);
+
+ auto ciphertext = std::unique_ptr<unsigned char[]>(
+ new unsigned char[len + 50]); // give enough room for padding
+ int outlen, tmplen;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+
+ auto cipherFunc = dhimpl->getCipherFunc();
+
+ // init openssl cipher context
+ if (dhimpl->m_skAlgo == "AES") {
+ int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+ EVP_DecryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+ dhimpl->m_key + keySize);
+ } else if (dhimpl->m_skAlgo == "Blowfish") {
+ int keySize = dhimpl->m_keySize > 128 ? dhimpl->m_keySize / 8 : 16;
+ EVP_DecryptInit_ex(ctx, cipherFunc, nullptr, nullptr,
+ dhimpl->m_key + keySize);
+ EVP_CIPHER_CTX_set_key_length(ctx, keySize);
+ LOGDH("DHencrypt: BF keysize is %d", keySize);
+ EVP_DecryptInit_ex(ctx, nullptr, nullptr, dhimpl->m_key, nullptr);
+ } else if (dhimpl->m_skAlgo == "DESede") {
+ EVP_DecryptInit_ex(ctx, cipherFunc, nullptr, dhimpl->m_key,
+ dhimpl->m_key + 24);
+ }
+
+ if (!EVP_DecryptUpdate(ctx, ciphertext.get(), &outlen, cleartext, len)) {
+ LOGDH(" DHencrypt: enc update ret nullptr");
+ return nullptr;
+ }
+ /* Buffer passed to EVP_EncryptFinal() must be after data just
+ * encrypted to avoid overwriting it.
+ */
+ tmplen = 0;
+
+ if (!EVP_DecryptFinal_ex(ctx, ciphertext.get() + outlen, &tmplen)) {
+ LOGDH("DHencrypt: enc final ret nullptr");
+ return nullptr;
+ }
+
+ outlen += tmplen;
+
+ EVP_CIPHER_CTX_free(ctx);
+
+ LOGDH("DHencrypt: in len is %d, out len is %d", len, outlen);
+
+ *retLen = outlen;
+ return ciphertext.release();
+}
+
+// std::shared_ptr<CacheableBytes> decrypt(const uint8_t * ciphertext, int len)
+// {
+// LOGDH("DH: Used unimplemented decrypt!");
+// return nullptr;
+//}
+
+bool gf_verifyDH(void *dhCtx, const char *subject,
+ const unsigned char *challenge, int challengeLen,
+ const unsigned char *response, int responseLen, int *reason) {
+ DHImpl *dhimpl = reinterpret_cast<DHImpl *>(dhCtx);
+
+ LOGDH(" In Verify - looking for subject %s", subject);
+
+ EVP_PKEY *evpkey = nullptr;
+ X509 *cert = nullptr;
+
+ char *certsubject = nullptr;
+
+ int32_t count = static_cast<int32_t>(dhimpl->m_serverCerts.size());
+ if (count == 0) {
+ *reason = DH_ERR_NO_CERTIFICATES;
+ return false;
+ }
+
+ for (int item = 0; item < count; item++) {
+ certsubject = X509_NAME_oneline(
+ X509_get_subject_name(dhimpl->m_serverCerts[item]), nullptr, 0);
+
+ // Ignore first letter for comparision, openssl adds / before subject name
+ // e.g. /CN=geode1
+ if (strcmp(certsubject + 1, subject) == 0) {
+ evpkey = X509_get_pubkey(dhimpl->m_serverCerts[item]);
+ cert = dhimpl->m_serverCerts[item];
+ LOGDH("Found subject [%s] in stored certificates", certsubject);
+ break;
+ }
+ }
+
+ if (evpkey == nullptr || cert == nullptr) {
+ *reason = DH_ERR_SUBJECT_NOT_FOUND;
+ LOGDH("Certificate not found!");
+ return false;
+ }
+
+ const ASN1_OBJECT *macobj;
+ const X509_ALGOR *algorithm = nullptr;
+ X509_ALGOR_get0(&macobj, nullptr, nullptr, algorithm);
+ if (algorithm == nullptr) {
+ LOGDH("algo is null \n");
+ }
+
+ const EVP_MD *signatureDigest = EVP_get_digestbyobj(macobj);
+ LOGDH("after EVP_get_digestbyobj : err(%d): %s", ERR_get_error(),
+ ERR_error_string(ERR_get_error(), nullptr));
+ EVP_MD_CTX *signatureCtx = EVP_MD_CTX_new();
+
+ int result1 = EVP_VerifyInit_ex(signatureCtx, signatureDigest, nullptr);
+ LOGDH("after EVP_VerifyInit_ex ret %d : err(%d): %s", result1,
+ ERR_get_error(), ERR_error_string(ERR_get_error(), nullptr));
+ LOGDH(" Result of VerifyInit is %s \n", ERR_lib_error_string(result1));
+ LOGDH(" Result of VerifyInit is %s \n", ERR_func_error_string(result1));
+ LOGDH(" Result of VerifyInit is %s \n", ERR_reason_error_string(result1));
+
+ LOGDH(" Result of VerifyInit is %d", result1);
+
+ int result2 = EVP_VerifyUpdate(signatureCtx, challenge, challengeLen);
+ LOGDH(" Result of VerifyUpdate is %d", result2);
+
+ int result3 = EVP_VerifyFinal(signatureCtx, response, responseLen, evpkey);
+ LOGDH(" Result of VerifyFinal is %d", result3);
+
+ bool result = (result1 == 1 && result2 == 1 && result3 == 1);
+
+ EVP_MD_CTX_free(signatureCtx);
+
+ if (result == false) {
+ *reason = DH_ERR_INVALID_SIGN;
+ }
+
+ return result;
+}
+
+int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey) {
+ DH_PUBKEY *pk = nullptr;
+ X509_ALGOR *a;
+ ASN1_OBJECT *o;
+ unsigned char *s, *p = nullptr;
+ int i;
+ ASN1_INTEGER *asn1int = nullptr;
+ DH *dh = EVP_PKEY_get1_DH(pkey);
+
+ if (x == nullptr) return (0);
+
+ if ((pk = DH_PUBKEY_new()) == nullptr) goto err;
+ a = pk->algor;
+
+ LOGDH(" key type for OBJ NID is %d", EVP_PKEY_base_id(pkey));
+
+ /* set the algorithm id */
+ if ((o = OBJ_nid2obj(EVP_PKEY_base_id(pkey))) == nullptr) goto err;
+ ASN1_OBJECT_free(a->algorithm);
+ a->algorithm = o;
+
+ /* Set the parameter list */
+ if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
+ if ((a->parameter == nullptr) || (a->parameter->type != V_ASN1_NULL)) {
+ ASN1_TYPE_free(a->parameter);
+ if (!(a->parameter = ASN1_TYPE_new())) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ a->parameter->type = V_ASN1_NULL;
+ }
+ } else if (EVP_PKEY_base_id(pkey) == EVP_PKEY_DH) {
+ unsigned char *pp;
+ ASN1_TYPE_free(a->parameter);
+ if ((i = i2d_DHparams(dh, nullptr)) <= 0) goto err;
+ if (!(p = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i)))) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ pp = p;
+ i2d_DHparams(dh, &pp);
+ if (!(a->parameter = ASN1_TYPE_new())) {
+ OPENSSL_free(p);
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ a->parameter->type = V_ASN1_SEQUENCE;
+ if (!(a->parameter->value.sequence = ASN1_STRING_new())) {
+ OPENSSL_free(p);
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!ASN1_STRING_set(a->parameter->value.sequence, p, i)) {
+ OPENSSL_free(p);
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ OPENSSL_free(p);
+ } else if (1) {
+ X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM);
+ goto err;
+ }
+
+ const BIGNUM *pub_key, *priv_key;
+ DH_get0_key(dh, &pub_key, &priv_key);
+
+ asn1int = BN_to_ASN1_INTEGER(pub_key, nullptr);
+ if ((i = i2d_ASN1_INTEGER(asn1int, nullptr)) <= 0) goto err;
+ if ((s = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i + 1))) ==
+ nullptr) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p = s;
+ i2d_ASN1_INTEGER(asn1int, &p);
+ if (!ASN1_BIT_STRING_set(static_cast<ASN1_STRING *>(pk->public_key), s, i)) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ /* Set number of unused bits to zero */
+ pk->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ pk->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+ OPENSSL_free(s);
+
+ if (*x != nullptr) DH_PUBKEY_free(*x);
+
+ *x = pk;
+
+ return 1;
+err:
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (pk != nullptr) DH_PUBKEY_free(pk);
+ return 0;
+}
+
+EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key) {
+ EVP_PKEY *ret = nullptr;
+ decltype(asn1_string_st::length) j;
+ const unsigned char *p;
+ const unsigned char *cp;
+ X509_ALGOR *a;
+ ASN1_INTEGER *asn1int = nullptr;
+
+ if (key == nullptr) {
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+
+ if (key->pkey != nullptr) {
+ EVP_PKEY_up_ref(key->pkey);
+ return (key->pkey);
+ }
+
+ if (key->public_key == nullptr) {
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+
+ if ((ret = EVP_PKEY_new()) == nullptr) {
+ X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+
+ LOGDH(" DHPUBKEY evppkey type is %d", EVP_PKEY_base_id(ret));
+
+ /* the parameters must be extracted before the public key */
+
+ a = key->algor;
+
+ if (EVP_PKEY_base_id(ret) == EVP_PKEY_DH) {
+ if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) {
+ if ((EVP_PKEY_set1_DH(ret, DH_new())) == 0) {
+ X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+ cp = p = a->parameter->value.sequence->data;
+ j = a->parameter->value.sequence->length;
+ DH *dh = EVP_PKEY_get1_DH(ret);
+ if (!d2i_DHparams(&dh, &cp, j)) {
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+ }
+ }
+
+ p = key->public_key->data;
+ j = key->public_key->length;
+
+ asn1int = d2i_ASN1_INTEGER(nullptr, &p, j);
+ LOGDH("after d2i asn1 integer ptr is %p", asn1int);
+
+ DH *dh = EVP_PKEY_get1_DH(ret);
+ DH_set0_key(dh, ASN1_INTEGER_to_BN(asn1int, nullptr), nullptr);
+ // LOGDH(" after asn1int to bn ptr is %p", ret->pkey.dh->pub_key);
+
+ key->pkey = ret;
+ EVP_PKEY_up_ref(ret);
+
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ return (ret);
+}
diff --git a/cryptoimpl/DHImpl.hpp b/cryptoimpl/DHImpl.hpp
new file mode 100644
index 0000000..94b49a5
--- /dev/null
+++ b/cryptoimpl/DHImpl.hpp
@@ -0,0 +1,100 @@
+#pragma once
+
+#ifndef GEODE_CRYPTOIMPL_DHIMPL_H_
+#define GEODE_CRYPTOIMPL_DHIMPL_H_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 <openssl/asn1t.h>
+#include <openssl/dh.h>
+#include <openssl/x509.h>
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "cryptoimpl_export.h"
+
+#define DH_ERR_NO_ERROR 0
+#define DH_ERR_UNSUPPORTED_ALGO 1
+#define DH_ERR_ILLEGAL_KEYSIZE 2
+#define DH_ERR_SUBJECT_NOT_FOUND 3
+#define DH_ERR_NO_CERTIFICATES 4
+#define DH_ERR_INVALID_SIGN 5
+
+#ifdef _DEBUG
+#define LOGDH printf
+#else
+#define LOGDH(...)
+#endif
+
+// We need to declare our own structures and macros for
+// DH public key x509 encoding because it's not available in
+// OpenSSL yet.
+typedef struct DH_pubkey_st {
+ X509_ALGOR* algor;
+ ASN1_BIT_STRING* public_key;
+ EVP_PKEY* pkey;
+} DH_PUBKEY;
+
+extern "C" {
+CRYPTOIMPL_EXPORT int gf_initDhKeys(void** dhCtx, const char* dhAlgo,
+ const char* ksPath);
+CRYPTOIMPL_EXPORT void gf_clearDhKeys(void* dhCtx);
+CRYPTOIMPL_EXPORT unsigned char* gf_getPublicKey(void* dhCtx, int* len);
+CRYPTOIMPL_EXPORT void gf_setPublicKeyOther(void* dhCtx,
+ const unsigned char* pubkey,
+ int length);
+CRYPTOIMPL_EXPORT void gf_computeSharedSecret(void* dhCtx);
+CRYPTOIMPL_EXPORT unsigned char* gf_encryptDH(void* dhCtx,
+ const unsigned char* cleartext,
+ int len, int* retLen);
+CRYPTOIMPL_EXPORT unsigned char* gf_decryptDH(void* dhCtx,
+ const unsigned char* cleartext,
+ int len, int* retLen);
+CRYPTOIMPL_EXPORT bool gf_verifyDH(void* dhCtx, const char* subject,
+ const unsigned char* challenge,
+ int challengeLen,
+ const unsigned char* response,
+ int responseLen, int* reason);
+}
+
+class DHImpl {
+ public:
+ DH* m_dh;
+ std::string m_skAlgo;
+ int m_keySize;
+ BIGNUM* m_pubKeyOther;
+ unsigned char m_key[128];
+ std::vector<X509*> m_serverCerts;
+
+ const EVP_CIPHER* getCipherFunc();
+ int setSkAlgo(const char* skalgo);
+
+ DHImpl() : m_dh(nullptr), m_keySize(0), m_pubKeyOther(nullptr) {
+ /* adongre
+ * CID 28924: Uninitialized scalar field (UNINIT_CTOR)
+ */
+ std::memset(m_key, 0, sizeof(m_key));
+ }
+ static bool m_init;
+};
+
+bool DHImpl::m_init = false;
+
+#endif // GEODE_CRYPTOIMPL_DHIMPL_H_
diff --git a/templates/security/CMakeLists.txt b/dhimpl/CMakeLists.txt
similarity index 72%
copy from templates/security/CMakeLists.txt
copy to dhimpl/CMakeLists.txt
index 36ce124..538b9f9 100644
--- a/templates/security/CMakeLists.txt
+++ b/dhimpl/CMakeLists.txt
@@ -13,34 +13,33 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-cmake_minimum_required(VERSION 3.10)
-project(templates.security LANGUAGES CXX)
+project(DHImpl LANGUAGES CXX)
-add_library(securityImpl SHARED
- UserPasswordAuthInit.cpp
- UserPasswordAuthInit.hpp
- CMakeLists.txt.forInstall
+add_library(DHImpl SHARED
+ DHImpl.cpp
+ DHImpl.hpp
)
-set_target_properties(securityImpl PROPERTIES
+set_target_properties(DHImpl PROPERTIES
FOLDER cpp/test/integration
)
include(GenerateExportHeader)
-generate_export_header(securityImpl)
+generate_export_header(DHImpl)
-target_include_directories(securityImpl
+target_include_directories(DHImpl
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
-target_link_libraries(securityImpl
+target_link_libraries(DHImpl
PUBLIC
apache-geode
OpenSSL::Crypto
+ c++11
PRIVATE
openssl-compat
_WarningsAsError
)
-add_clangformat(securityImpl)
+add_clangformat(DHImpl)
diff --git a/dhimpl/DHImpl.cpp b/dhimpl/DHImpl.cpp
new file mode 100644
index 0000000..3b7ea74
--- /dev/null
+++ b/dhimpl/DHImpl.cpp
@@ -0,0 +1,612 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "DHImpl.hpp"
+
+#include <openssl/aes.h>
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include <cctype>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+
+static DH *m_dh = nullptr;
+static std::string m_skAlgo;
+static int m_keySize = 0;
+static BIGNUM *m_pubKeyOther = nullptr;
+static unsigned char m_key[128] = {0};
+static std::vector<X509 *> m_serverCerts;
+
+static const char *dhP =
+ "13528702063991073999718992897071702177131142188276542919088770094024269"
+ "73079899070080419278066109785292538223079165925365098181867673946"
+ "34756714063947534092593553024224277712367371302394452615862654308"
+ "11180902979719649450105660478776364198726078338308557022096810447"
+ "3500348898008043285865193451061481841186553";
+
+static const int dhL = 1023;
+
+static int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey);
+static EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key);
+static const EVP_CIPHER *getCipherFunc();
+static int setSkAlgo(const char *skalgo);
+
+ASN1_SEQUENCE(
+ DH_PUBKEY) = {ASN1_SIMPLE(DH_PUBKEY, algor, X509_ALGOR),
+ ASN1_SIMPLE(DH_PUBKEY, public_key,
+ ASN1_BIT_STRING)} ASN1_SEQUENCE_END(DH_PUBKEY)
+
+ // This gives us the i2d/d2i x.509 (ASN1 DER) encode/decode functions
+ IMPLEMENT_ASN1_FUNCTIONS(DH_PUBKEY)
+
+ // Returns Error code
+ int gf_initDhKeys(const char *dhAlgo, const char *ksPath) {
+ int errorCode = DH_ERR_NO_ERROR; // No error;
+
+ // ksPath can be null
+ if (m_dh || !dhAlgo || strlen(dhAlgo) == 0) {
+ return errorCode;
+ }
+
+ // set the symmetric cipher algorithm name
+ errorCode = setSkAlgo(dhAlgo);
+ if (errorCode != DH_ERR_NO_ERROR) {
+ return errorCode;
+ }
+
+ // do add-all here or outside in DS::connect?
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ m_dh = DH_new();
+
+ BIGNUM *pbn = nullptr;
+ BIGNUM *gbn = nullptr;
+ DH_get0_pqg(m_dh, const_cast<const BIGNUM **>(&pbn), nullptr,
+ const_cast<const BIGNUM **>(&gbn));
+ BN_dec2bn(&pbn, dhP);
+
+ LOGDH(" DHInit: P ptr is %p", pbn);
+ LOGDH(" DHInit: G ptr is %p", gbn);
+ LOGDH(" DHInit: length is %d", DH_get_length(m_dh));
+
+ BN_dec2bn(&gbn, dhP);
+
+ DH_set_length(m_dh, dhL);
+
+ DH_generate_key(m_dh);
+
+ const BIGNUM *pub_key, *priv_key;
+ DH_get0_key(m_dh, &pub_key, &priv_key);
+
+ int codes = 0;
+ DH_check(m_dh, &codes);
+ LOGDH(" DHInit: DH_check codes is 0x%04X", codes);
+ LOGDH(" DHInit: DH_size is %d", DH_size(m_dh));
+
+ // load the server's RSA public key for server authentication
+ // note that OpenSSL 0.9.8g has a bug where it can read only the first one in
+ // the keystore
+
+ LOGDH(" Loading keystore...");
+
+ if (ksPath == nullptr || strlen(ksPath) == 0) {
+ LOGDH("Property \"security-client-kspath\" 's value is nullptr.");
+ return errorCode;
+ }
+ FILE *keyStoreFP = nullptr;
+ keyStoreFP = fopen(ksPath, "r");
+
+ LOGDH(" kspath is [%s]", ksPath);
+ LOGDH(" keystore FILE ptr is %p", keyStoreFP);
+
+ // Read from pem file and put into.
+ X509 *cert = nullptr;
+ do {
+ cert = PEM_read_X509(keyStoreFP, nullptr, nullptr, nullptr);
+
+ if (cert != nullptr) {
+ m_serverCerts.push_back(cert);
+ }
+ } while (cert != nullptr);
+
+ LOGDH(" Total certificats imported # %zd", m_serverCerts.size());
+
+ fclose(keyStoreFP);
+
+ return errorCode;
+}
+
+void gf_clearDhKeys(void) {
+ if (m_dh != nullptr) {
+ DH_free(m_dh);
+ m_dh = nullptr;
+ }
+
+ std::vector<X509 *>::const_iterator iter;
+ for (iter = m_serverCerts.begin(); iter != m_serverCerts.end(); ++iter) {
+ X509_free(*iter);
+ }
+
+ m_serverCerts.clear();
+
+ if (m_pubKeyOther != nullptr) {
+ BN_free(m_pubKeyOther);
+ m_pubKeyOther = nullptr;
+ }
+
+ memset(m_key, 0, 128);
+
+ EVP_cleanup();
+}
+
+unsigned char *gf_getPublicKey(int *pLen) {
+ const BIGNUM *pub_key, *priv_key;
+ DH_get0_key(m_dh, &pub_key, &priv_key);
+
+ if (pub_key == nullptr || pLen == nullptr) {
+ return nullptr;
+ }
+
+ int numBytes = BN_num_bytes(pub_key);
+
+ if (numBytes <= 0) {
+ return nullptr;
+ }
+
+ EVP_PKEY *evppubkey = EVP_PKEY_new();
+ LOGDH(" before assign DH ptr is %p", m_dh);
+ EVP_PKEY_assign_DH(evppubkey, m_dh);
+ LOGDH(" after assign DH ptr is %p", m_dh);
+ DH_PUBKEY *dhpubkey = nullptr;
+ DH_PUBKEY_set(&dhpubkey, evppubkey);
+ int len = i2d_DH_PUBKEY(dhpubkey, nullptr);
+ unsigned char *pubkey = new unsigned char[len];
+ unsigned char *temp = pubkey;
+ //
+ // Note, this temp pointer is needed because OpenSSL increments the pointer
+ // passed in
+ // so that following encoding can be done at the current output location,
+ // this will cause a problem if we try to free the pointer which has been
+ // moved by OpenSSL.
+ //
+ i2d_DH_PUBKEY(dhpubkey, &temp);
+
+ // TODO: uncomment this - causing problem in computeSecret?
+ // DH_PUBKEY_free(dhpubkey);
+ // EVP_PKEY_free(evppubkey);
+
+ LOGDH(" after evp free DH ptr is %p", m_dh);
+ *pLen = len;
+ return pubkey;
+}
+
+void gf_setPublicKeyOther(const unsigned char *pubkey, int length) {
+ if (m_pubKeyOther != nullptr) {
+ BN_free(m_pubKeyOther);
+ m_pubKeyOther = nullptr;
+ }
+
+ const unsigned char *temp = pubkey;
+ DH_PUBKEY *dhpubkey = d2i_DH_PUBKEY(nullptr, &temp, length);
+ LOGDH(" setPubKeyOther: after d2i_dhpubkey ptr is %p", dhpubkey);
+ EVP_PKEY *evppkey = DH_PUBKEY_get(dhpubkey);
+ LOGDH(" setPubKeyOther: after dhpubkey get evp ptr is %p", evppkey);
+ LOGDH(" setPubKeyOther: before BNdup ptr is %p", m_pubKeyOther);
+
+ const BIGNUM *pub_key, *priv_key;
+ DH *dh = EVP_PKEY_get1_DH(evppkey);
+ DH_get0_key(dh, &pub_key, &priv_key);
+ m_pubKeyOther = BN_dup(pub_key);
+ LOGDH(" setPubKeyOther: after BNdup ptr is %p", m_pubKeyOther);
+ EVP_PKEY_free(evppkey);
+ DH_PUBKEY_free(dhpubkey);
+
+#ifdef _DEBUG
+ int codes = 0;
+ int ret = DH_check_pub_key(m_dh, m_pubKeyOther, &codes);
+ LOGDH(" DHInit: DH_check_pub_key ret %d", ret);
+ LOGDH(" DHInit: DH check_pub_key codes is 0x%04X", codes);
+#endif
+}
+
+void gf_computeSharedSecret() {
+ LOGDH("COMPUTE: DH ptr %p, pubkeyOther ptr %p", m_dh, m_pubKeyOther);
+
+ LOGDH("DHcomputeKey DHSize is %d", DH_size(m_dh));
+#ifdef _DEBUG
+ int ret = DH_compute_key(m_key, m_pubKeyOther, m_dh);
+ LOGDH("DHcomputeKey ret %d : Compute err(%d): %s", ret, ERR_get_error(),
+ ERR_error_string(ERR_get_error(), nullptr));
+#endif
+}
+
+int setSkAlgo(const char *skalgo) {
+ int errCode = DH_ERR_NO_ERROR;
+
+ std::string inAlgo(skalgo);
+ size_t colIdx = inAlgo.find(':');
+ std::string algoStr =
+ (colIdx == std::string::npos) ? inAlgo : inAlgo.substr(0, colIdx);
+ int keySize = 0;
+
+ // Convert input algo to lower case to support case insensitivity
+ for (unsigned int i = 0; i < algoStr.size(); i++) {
+ algoStr[i] = tolower(algoStr[i]);
+ }
+
+ if (algoStr == "aes") {
+ keySize = (colIdx == std::string::npos)
+ ? 128
+ : atoi(inAlgo.substr(colIdx + 1).c_str());
+ if (keySize == 128 || keySize == 192 || keySize == 256) {
+ m_skAlgo = "AES";
+ m_keySize = keySize;
+ } else {
+ return DH_ERR_ILLEGAL_KEYSIZE;
+ }
+ } else if (algoStr == "blowfish") {
+ keySize = (colIdx == std::string::npos)
+ ? 128
+ : atoi(inAlgo.substr(colIdx + 1).c_str());
+ if (keySize >= 128 && keySize <= 448) {
+ m_skAlgo = "Blowfish";
+ m_keySize = keySize;
+ } else {
+ return DH_ERR_ILLEGAL_KEYSIZE;
+ }
+ } else if (algoStr == "desede") { // No keysize should be given
+ if (colIdx == std::string::npos) {
+ m_skAlgo = "DESede";
+ m_keySize = 192;
+ } else {
+ return DH_ERR_ILLEGAL_KEYSIZE;
+ }
+ } else {
+ return DH_ERR_UNSUPPORTED_ALGO;
+ }
+
+ LOGDH(" DH: Got SK algo as %s", m_skAlgo.c_str());
+ LOGDH(" DH: Got keySize as %d", m_keySize);
+
+ return errCode;
+}
+
+const EVP_CIPHER *getCipherFunc() {
+ if (m_skAlgo == "AES") {
+ if (m_keySize == 192) {
+ return EVP_aes_192_cbc();
+ } else if (m_keySize == 256) {
+ return EVP_aes_256_cbc();
+ } else { // Default
+ return EVP_aes_128_cbc();
+ }
+ } else if (m_skAlgo == "Blowfish") {
+ return EVP_bf_cbc();
+ } else if (m_skAlgo == "DESede") {
+ return EVP_des_ede3_cbc();
+ } else {
+ LOGDH("ERROR: Unsupported DH Algorithm");
+ return nullptr;
+ }
+}
+
+unsigned char *gf_encryptDH(const unsigned char *cleartext, int len,
+ int *retLen) {
+ // Validation
+ if (cleartext == nullptr || len < 1 || retLen == nullptr) {
+ return nullptr;
+ }
+
+ LOGDH(" DH: gf_encryptDH using sk algo: %s, Keysize: %d", m_skAlgo.c_str(),
+ m_keySize);
+
+ auto ciphertext = std::unique_ptr<unsigned char[]>(
+ new unsigned char[len + 50]); // give enough room for padding
+ int outlen, tmplen;
+ auto ctx = EVP_CIPHER_CTX_new();
+
+ auto cipherFunc = getCipherFunc();
+
+ // init openssl cipher context
+ if (m_skAlgo == "AES") {
+ int keySize = m_keySize > 128 ? m_keySize / 8 : 16;
+ EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, m_key, m_key + keySize);
+ } else if (m_skAlgo == "Blowfish") {
+ int keySize = m_keySize > 128 ? m_keySize / 8 : 16;
+ EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, nullptr, m_key + keySize);
+ EVP_CIPHER_CTX_set_key_length(ctx, keySize);
+ LOGDH("DHencrypt: BF keysize is %d", keySize);
+ EVP_EncryptInit_ex(ctx, nullptr, nullptr, m_key, nullptr);
+ } else if (m_skAlgo == "DESede") {
+ EVP_EncryptInit_ex(ctx, cipherFunc, nullptr, m_key, m_key + 24);
+ }
+
+ if (!EVP_EncryptUpdate(ctx, ciphertext.get(), &outlen, cleartext, len)) {
+ LOGDH(" DHencrypt: enc update ret nullptr");
+ return nullptr;
+ }
+ /* Buffer passed to EVP_EncryptFinal() must be after data just
+ * encrypted to avoid overwriting it.
+ */
+ tmplen = 0;
+
+ if (!EVP_EncryptFinal_ex(ctx, ciphertext.get() + outlen, &tmplen)) {
+ LOGDH("DHencrypt: enc final ret nullptr");
+ return nullptr;
+ }
+
+ outlen += tmplen;
+
+ EVP_CIPHER_CTX_cleanup(ctx);
+
+ LOGDH("DHencrypt: in len is %d, out len is %d", len, outlen);
+
+ *retLen = outlen;
+ return ciphertext.release();
+}
+
+// std::shared_ptr<CacheableBytes> decrypt(const uint8_t * ciphertext, int
+// len)
+// {
+// LOGDH("DH: Used unimplemented decrypt!");
+// return nullptr;
+//}
+
+bool gf_verifyDH(const char *subject, const unsigned char *challenge,
+ int challengeLen, const unsigned char *response,
+ int responseLen, int *reason) {
+ LOGDH(" In Verify - looking for subject %s", subject);
+
+ EVP_PKEY *evpkey = nullptr;
+ X509 *cert = nullptr;
+
+ char *certsubject = nullptr;
+
+ int32_t count = static_cast<int32_t>(m_serverCerts.size());
+ if (count == 0) {
+ *reason = DH_ERR_NO_CERTIFICATES;
+ return false;
+ }
+
+ for (int item = 0; item < count; item++) {
+ certsubject = X509_NAME_oneline(X509_get_subject_name(m_serverCerts[item]),
+ nullptr, 0);
+
+ // Ignore first letter for comparision, openssl adds / before subject name
+ // e.g. /CN=geode1
+ if (strcmp(certsubject + 1, subject) == 0) {
+ evpkey = X509_get_pubkey(m_serverCerts[item]);
+ cert = m_serverCerts[item];
+ LOGDH("Found subject [%s] in stored certificates", certsubject);
+ break;
+ }
+ }
+
+ if (evpkey == nullptr || cert == nullptr) {
+ *reason = DH_ERR_SUBJECT_NOT_FOUND;
+ LOGDH("Certificate not found!");
+ return false;
+ }
+
+ const ASN1_OBJECT *macobj;
+ const X509_ALGOR *algorithm = nullptr;
+ X509_ALGOR_get0(&macobj, nullptr, nullptr, algorithm);
+
+ const EVP_MD *signatureDigest = EVP_get_digestbyobj(macobj);
+ EVP_MD_CTX *signatureCtx = EVP_MD_CTX_new();
+
+ int result1 = EVP_VerifyInit_ex(signatureCtx, signatureDigest, nullptr);
+ LOGDH(" Result of VerifyInit is %d", result1);
+
+ int result2 = EVP_VerifyUpdate(signatureCtx, challenge, challengeLen);
+ LOGDH(" Result of VerifyUpdate is %d", result2);
+
+ int result3 = EVP_VerifyFinal(signatureCtx, response, responseLen, evpkey);
+ LOGDH(" Result of VerifyFinal is %d", result3);
+
+ bool result = (result1 == 1 && result2 == 1 && result3 == 1);
+
+ EVP_MD_CTX_free(signatureCtx);
+
+ if (result == false) {
+ *reason = DH_ERR_INVALID_SIGN;
+ }
+
+ return result;
+}
+
+int DH_PUBKEY_set(DH_PUBKEY **x, EVP_PKEY *pkey) {
+ DH_PUBKEY *pk = nullptr;
+ X509_ALGOR *a;
+ ASN1_OBJECT *o;
+ unsigned char *s, *p = nullptr;
+ int i;
+ ASN1_INTEGER *asn1int = nullptr;
+ DH *dh = EVP_PKEY_get1_DH(pkey);
+
+ if (x == nullptr) return (0);
+
+ if ((pk = DH_PUBKEY_new()) == nullptr) goto err;
+ a = pk->algor;
+
+ LOGDH(" key type for OBJ NID is %d", EVP_PKEY_base_id(pkey));
+
+ /* set the algorithm id */
+ if ((o = OBJ_nid2obj(EVP_PKEY_base_id(pkey))) == nullptr) goto err;
+ ASN1_OBJECT_free(a->algorithm);
+ a->algorithm = o;
+
+ /* Set the parameter list */
+ if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
+ if ((a->parameter == nullptr) || (a->parameter->type != V_ASN1_NULL)) {
+ ASN1_TYPE_free(a->parameter);
+ if (!(a->parameter = ASN1_TYPE_new())) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ a->parameter->type = V_ASN1_NULL;
+ }
+ } else if (EVP_PKEY_base_id(pkey) == EVP_PKEY_DH) {
+ unsigned char *pp;
+
+ const BIGNUM *pub_key, *priv_key;
+ DH_get0_key(dh, &pub_key, &priv_key);
+ ASN1_TYPE_free(a->parameter);
+ if ((i = i2d_DHparams(dh, nullptr)) <= 0) goto err;
+ if (!(p = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i)))) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ pp = p;
+ i2d_DHparams(dh, &pp);
+ if (!(a->parameter = ASN1_TYPE_new())) {
+ OPENSSL_free(p);
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ a->parameter->type = V_ASN1_SEQUENCE;
+ if (!(a->parameter->value.sequence = ASN1_STRING_new())) {
+ OPENSSL_free(p);
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!ASN1_STRING_set(a->parameter->value.sequence, p, i)) {
+ OPENSSL_free(p);
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ OPENSSL_free(p);
+ } else if (1) {
+ X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM);
+ goto err;
+ }
+
+ const BIGNUM *pub_key, *priv_key;
+ DH_get0_key(dh, &pub_key, &priv_key);
+
+ asn1int = BN_to_ASN1_INTEGER(pub_key, nullptr);
+ if ((i = i2d_ASN1_INTEGER(asn1int, nullptr)) <= 0) goto err;
+ if ((s = reinterpret_cast<unsigned char *>(OPENSSL_malloc(i + 1))) ==
+ nullptr) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p = s;
+ i2d_ASN1_INTEGER(asn1int, &p);
+ if (!ASN1_BIT_STRING_set(pk->public_key, s, i)) {
+ X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ /* Set number of unused bits to zero */
+ pk->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ pk->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+ OPENSSL_free(s);
+
+ if (*x != nullptr) DH_PUBKEY_free(*x);
+
+ *x = pk;
+
+ return 1;
+err:
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (pk != nullptr) DH_PUBKEY_free(pk);
+ return 0;
+}
+
+EVP_PKEY *DH_PUBKEY_get(DH_PUBKEY *key) {
+ EVP_PKEY *ret = nullptr;
+ decltype(asn1_string_st::length) j;
+ const unsigned char *p;
+ const unsigned char *cp;
+ X509_ALGOR *a;
+ ASN1_INTEGER *asn1int = nullptr;
+
+ if (key == nullptr) {
+ return (nullptr);
+ }
+
+ if (key->pkey != nullptr) {
+ EVP_PKEY_up_ref(key->pkey);
+ return (key->pkey);
+ }
+
+ if (key->public_key == nullptr) {
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+
+ if ((ret = EVP_PKEY_new()) == nullptr) {
+ X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+
+ LOGDH(" DHPUBKEY evppkey type is %d", EVP_PKEY_base_id(ret));
+
+ /* the parameters must be extracted before the public key */
+
+ a = key->algor;
+
+ if (EVP_PKEY_base_id(ret) == EVP_PKEY_DH) {
+ if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) {
+ if ((EVP_PKEY_set1_DH(ret, DH_new())) == 0) {
+ X509err(X509_F_X509_PUBKEY_DECODE, ERR_R_MALLOC_FAILURE);
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+ cp = p = a->parameter->value.sequence->data;
+ j = a->parameter->value.sequence->length;
+ DH *dh = EVP_PKEY_get1_DH(ret);
+ if (!d2i_DHparams(&dh, &cp, j)) {
+ if (asn1int != nullptr) ASN1_INTEGER_free(asn1int);
+ if (ret != nullptr) EVP_PKEY_free(ret);
+ return (nullptr);
+ }
+ }
+ }
+
+ p = key->public_key->data;
+ j = key->public_key->length;
+
+ asn1int = d2i_ASN1_INTEGER(nullptr, &p, j);
+ LOGDH("after d2i asn1 integer ptr is %p", asn1int);
+
+ DH *dh = EVP_PKEY_get1_DH(ret);
+ DH_set0_key(dh, ASN1_INTEGER_to_BN(asn1int, nullptr), nullptr);
+
+ key->pkey = ret;
+ EVP_PKEY_up_ref(key->pkey);
+
+ if (asn1int) {
+ ASN1_INTEGER_free(asn1int);
+ }
+ return (ret);
+}
diff --git a/dhimpl/DHImpl.hpp b/dhimpl/DHImpl.hpp
new file mode 100644
index 0000000..38ba3c8
--- /dev/null
+++ b/dhimpl/DHImpl.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#ifndef GEODE_DHIMPL_DHIMPL_H_
+#define GEODE_DHIMPL_DHIMPL_H_
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 <openssl-compat.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+
+#include <string>
+#include <vector>
+
+#include "dhimpl_export.h"
+
+#define DH_ERR_NO_ERROR 0
+#define DH_ERR_UNSUPPORTED_ALGO 1
+#define DH_ERR_ILLEGAL_KEYSIZE 2
+#define DH_ERR_SUBJECT_NOT_FOUND 3
+#define DH_ERR_NO_CERTIFICATES 4
+#define DH_ERR_INVALID_SIGN 5
+
+#ifdef _DEBUG
+#define LOGDH printf
+#else
+#define LOGDH(...)
+#endif
+
+// We need to declare our own structures and macros for
+// DH public key x509 encoding because it's not available in
+// OpenSSL yet.
+typedef struct DH_pubkey_st {
+ X509_ALGOR* algor;
+ ASN1_BIT_STRING* public_key;
+ EVP_PKEY* pkey;
+} DH_PUBKEY;
+
+extern "C" {
+DHIMPL_EXPORT int gf_initDhKeys(const char* dhAlgo, const char* ksPath);
+DHIMPL_EXPORT void gf_clearDhKeys(void);
+DHIMPL_EXPORT unsigned char* gf_getPublicKey(int* len);
+DHIMPL_EXPORT void gf_setPublicKeyOther(const unsigned char* pubkey,
+ int length);
+DHIMPL_EXPORT void gf_computeSharedSecret(void);
+DHIMPL_EXPORT unsigned char* gf_encryptDH(const unsigned char* cleartext,
+ int len, int* retLen);
+DHIMPL_EXPORT bool gf_verifyDH(const char* subject,
+ const unsigned char* challenge, int challengeLen,
+ const unsigned char* response, int responseLen,
+ int* reason);
+}
+
+#endif // GEODE_DHIMPL_DHIMPL_H_
diff --git a/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb b/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb
index c9314f5..caa55ad 100644
--- a/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb
+++ b/docs/geode-native-docs-cpp/configuring/sysprops.html.md.erb
@@ -256,7 +256,7 @@ See [SSL Client/Server Communication](../security/sslclientserver.html).
</tr>
<tr class="odd">
<td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
<td>null</td>
</tr>
<tr class="even">
diff --git a/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb b/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb
index b7f73c6..81eba0e 100644
--- a/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb
+++ b/docs/geode-native-docs-cpp/security/security-systemprops.html.md.erb
@@ -32,7 +32,7 @@ The table describes the security-related system properties in the `geode.propert
<tbody>
<tr class="odd">
<td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
</tr>
<tr class="even">
<td><code class="ph codeph">security-client-kspath</code></td>
diff --git a/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb b/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb
index 6191c59..ae58777 100644
--- a/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb
+++ b/docs/geode-native-docs-dotnet/configuring/sysprops.html.md.erb
@@ -256,7 +256,7 @@ See [SSL Client/Server Communication](../security/sslclientserver.html).
</tr>
<tr class="odd">
<td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
<td>null</td>
</tr>
<tr class="even">
diff --git a/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb b/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb
index b7f73c6..81eba0e 100644
--- a/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb
+++ b/docs/geode-native-docs-dotnet/security/security-systemprops.html.md.erb
@@ -32,7 +32,7 @@ The table describes the security-related system properties in the `geode.propert
<tbody>
<tr class="odd">
<td><code class="ph codeph">security-client-dhalgo</code></td>
-<td>Diffie-Hellman based credentials encryption is not supported.</td>
+<td>Returns the Diffie-Hellman secret key cipher algorithm.</td>
</tr>
<tr class="even">
<td><code class="ph codeph">security-client-kspath</code></td>
diff --git a/templates/security/CMakeLists.txt b/templates/security/CMakeLists.txt
index 36ce124..0bf308e 100644
--- a/templates/security/CMakeLists.txt
+++ b/templates/security/CMakeLists.txt
@@ -17,6 +17,8 @@ cmake_minimum_required(VERSION 3.10)
project(templates.security LANGUAGES CXX)
add_library(securityImpl SHARED
+ PkcsAuthInit.cpp
+ PkcsAuthInit.hpp
UserPasswordAuthInit.cpp
UserPasswordAuthInit.hpp
CMakeLists.txt.forInstall
diff --git a/templates/security/PkcsAuthInit.cpp b/templates/security/PkcsAuthInit.cpp
new file mode 100644
index 0000000..1150289
--- /dev/null
+++ b/templates/security/PkcsAuthInit.cpp
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "PkcsAuthInit.hpp"
+
+#include <openssl-compat.h>
+
+#include <cstdio>
+#include <string>
+
+#include <geode/CacheableBuiltins.hpp>
+#include <geode/ExceptionTypes.hpp>
+#include <geode/Properties.hpp>
+
+#include "geode/CacheableBuiltins.hpp"
+#include "geode/ExceptionTypes.hpp"
+#include "geode/Properties.hpp"
+#include "securityimpl_export.h"
+
+namespace apache {
+namespace geode {
+namespace client {
+
+extern "C" {
+SECURITYIMPL_EXPORT AuthInitialize* createPKCSAuthInitInstance() {
+ return new PKCSAuthInit();
+}
+
+uint8_t* createSignature(EVP_PKEY* key, X509* cert,
+ const unsigned char* inputBuffer,
+ uint32_t inputBufferLen, unsigned int* signatureLen) {
+ if (!key || !cert || !inputBuffer) {
+ return nullptr;
+ }
+
+ const ASN1_OBJECT* macobj;
+ X509_ALGOR_get0(&macobj, nullptr, nullptr, nullptr);
+ const EVP_MD* signatureDigest = EVP_get_digestbyobj(macobj);
+
+ EVP_MD_CTX* signatureCtx = EVP_MD_CTX_new();
+ uint8_t* signatureData = new uint8_t[EVP_PKEY_size(key)];
+
+ bool result = (EVP_SignInit_ex(signatureCtx, signatureDigest, nullptr) &&
+ EVP_SignUpdate(signatureCtx, inputBuffer, inputBufferLen) &&
+ EVP_SignFinal(signatureCtx, signatureData, signatureLen, key));
+
+ EVP_MD_CTX_free(signatureCtx);
+ if (result) {
+ return signatureData;
+ }
+ return nullptr;
+}
+
+bool readPKCSPublicPrivateKey(FILE* keyStoreFP, const char* keyStorePassword,
+ EVP_PKEY** outPrivateKey, X509** outCertificate) {
+ PKCS12* p12;
+
+ if (!keyStoreFP || !keyStorePassword || (keyStorePassword[0] == '\0')) {
+ return (false);
+ }
+
+ p12 = d2i_PKCS12_fp(keyStoreFP, nullptr);
+
+ if (p12) {
+ return (false);
+ }
+
+ if (!PKCS12_parse(p12, keyStorePassword, outPrivateKey, outCertificate,
+ nullptr)) {
+ return (false);
+ }
+
+ PKCS12_free(p12);
+
+ return (outPrivateKey && outCertificate);
+}
+
+bool openSSLInit() {
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ return true;
+}
+
+static bool s_initDone = openSSLInit();
+}
+// end of extern "C"
+
+std::shared_ptr<Properties> PKCSAuthInit::getCredentials(
+ const std::shared_ptr<Properties>& securityprops, const std::string&) {
+ if (!s_initDone) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "OpenSSL initialization failed.");
+ }
+ if (securityprops == nullptr || securityprops->getSize() <= 0) {
+ throw AuthenticationRequiredException(
+ "PKCSAuthInit::getCredentials: "
+ "No security-* properties are set.");
+ }
+
+ auto keyStoreptr = securityprops->find(KEYSTORE_FILE_PATH);
+
+ const char* keyStorePath = keyStoreptr->value().c_str();
+
+ if (!keyStorePath) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "key-store file path property KEYSTORE_FILE_PATH not set.");
+ }
+
+ auto aliasptr = securityprops->find(KEYSTORE_ALIAS);
+
+ const char* alias = aliasptr->value().c_str();
+
+ if (!alias) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "key-store alias property KEYSTORE_ALIAS not set.");
+ }
+
+ auto keyStorePassptr = securityprops->find(KEYSTORE_PASSWORD);
+
+ const char* keyStorePass = keyStorePassptr->value().c_str();
+
+ if (!keyStorePass) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "key-store password property KEYSTORE_PASSWORD not set.");
+ }
+
+ FILE* keyStoreFP = fopen(keyStorePath, "r");
+ if (!keyStoreFP) {
+ char msg[1024];
+ sprintf(msg, "PKCSAuthInit::getCredentials: Unable to open keystore %s",
+ keyStorePath);
+ throw AuthenticationFailedException(msg);
+ }
+
+ EVP_PKEY* privateKey = nullptr;
+ X509* cert = nullptr;
+
+ /* Read the Public and Private Key from keystore in file */
+ if (!readPKCSPublicPrivateKey(keyStoreFP, keyStorePass, &privateKey, &cert)) {
+ fclose(keyStoreFP);
+ char msg[1024];
+ sprintf(msg,
+ "PKCSAuthInit::getCredentials: Unable to read PKCS "
+ "public key from %s",
+ keyStorePath);
+ throw AuthenticationFailedException(msg);
+ }
+
+ fclose(keyStoreFP);
+
+ unsigned int lengthEncryptedData = 0;
+
+ auto signatureData = createSignature(
+ privateKey, cert, reinterpret_cast<const unsigned char*>(alias),
+ static_cast<uint32_t>(strlen(alias)), &lengthEncryptedData);
+ EVP_PKEY_free(privateKey);
+ X509_free(cert);
+ if (signatureData == nullptr) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "Unable to create signature");
+ }
+ auto signatureValPtr = CacheableBytes::create(
+ std::vector<int8_t>(signatureData, signatureData + lengthEncryptedData));
+
+ auto credentials = Properties::create();
+ credentials->insert(KEYSTORE_ALIAS, alias);
+ credentials->insert(CacheableString::create(SIGNATURE_DATA), signatureValPtr);
+ return credentials;
+}
+} // namespace client
+} // namespace geode
+} // namespace apache
diff --git a/templates/security/PkcsAuthInit.hpp b/templates/security/PkcsAuthInit.hpp
new file mode 100644
index 0000000..5e3c94a
--- /dev/null
+++ b/templates/security/PkcsAuthInit.hpp
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 __PKCSAUTHINIT__
+#define __PKCSAUTHINIT__
+
+#include <cstdio>
+#include <cstdlib>
+
+#pragma error_messages(off, macroredef)
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#pragma error_messages(on, macroredef)
+
+#include <geode/AuthInitialize.hpp>
+
+/**
+ * @file
+ */
+
+const char KEYSTORE_FILE_PATH[] = "security-keystorepath";
+
+const char KEYSTORE_ALIAS[] = "security-alias";
+
+const char KEYSTORE_PASSWORD[] = "security-keystorepass";
+
+const char SIGNATURE_DATA[] = "security-signature";
+
+namespace apache {
+namespace geode {
+namespace client {
+
+/**
+ * @class PKCSAuthInit Implementation PKCSAuthInit.hpp
+ * PKCSAuthInit API for getCredentials.
+ * The PKCSAuthInit class derives from AuthInitialize base class.
+ * It uses the provided alias, password and corresponding keystore to obtain the
+ * private key and
+ * encrypts data. This data is sent to server for authentication.
+ *
+ */
+
+class PKCSAuthInit : public AuthInitialize {
+ public:
+ PKCSAuthInit() = default;
+ ~PKCSAuthInit() noexcept override = default;
+
+ /**@brief initialize with the given set of security properties
+ * and return the credentials for the client as properties.
+ * @param props the set of security properties provided to the
+ * <code>DistributedSystem.connect</code> method
+ * @param server it is the ID of the current endpoint.
+ * The format expected is "host:port".
+ * @returns the credentials to be used for the given <code>server</code>
+ */
+ std::shared_ptr<Properties> getCredentials(
+ const std::shared_ptr<Properties>& securityprops,
+ const std::string& server) override;
+
+ /**
+ * @brief Invoked before the cache goes down.
+ */
+ void close() override { return; }
+
+ /**
+ * @brief private members
+ */
+
+ private:
+};
+} // namespace client
+} // namespace geode
+} // namespace apache
+#endif //__PKCSAUTHINIT__
diff --git a/tests/cli/CMakeLists.txt b/tests/cli/CMakeLists.txt
index 1d81e62..973a690 100644
--- a/tests/cli/CMakeLists.txt
+++ b/tests/cli/CMakeLists.txt
@@ -16,6 +16,7 @@
cmake_minimum_required(VERSION 3.10)
project(nativeclient.tests LANGUAGES NONE)
+add_subdirectory(PkcsWrapper)
add_subdirectory(QueryHelper)
add_subdirectory(PdxClassLibrary)
diff --git a/tests/cli/NewFwkLib/CacheServer.cs b/tests/cli/NewFwkLib/CacheServer.cs
index afa1025..8365786 100644
--- a/tests/cli/NewFwkLib/CacheServer.cs
+++ b/tests/cli/NewFwkLib/CacheServer.cs
@@ -4351,6 +4351,59 @@ private void checkUpdatedValue(TKey key, TVal value)
};
}
}
+ else
+ {
+ FwkInfo("Security Scheme is {0}", SecurityCode);
+ for (Int32 i = 0; i < userSize; i++)
+ {
+ Properties<string, string> userProp = new Properties<string, string>();
+ PkcsAuthInit pkcs = new PkcsAuthInit();
+ if (pkcs == null) {
+ FwkException("NULL PKCS Credential Generator");
+ }
+ userName = (String)userList[i];
+ string dataDir = Util.GetFwkLogDir(Util.SystemType) + "/data";
+ userProp.Insert(KeyStoreFileProp, GetKeyStoreDir(dataDir) +
+ userName + ".keystore");
+ userProp.Insert(KeyStoreAliasProp, userName);
+ userProp.Insert(KeyStorePasswordProp, "geode");
+ //mu_cache = pool.CreateSecureUserCache(userProp);
+ //IRegionService mu_cache = CacheHelper<TKey, TVal>.DCache.CreateAuthenticatedView(userProp, pool.Name);
+ IRegionService mu_cache = CacheHelper<TKey, TVal>.DCache.CreateAuthenticatedView(
+ CacheHelper<TKey, TVal>.GetPkcsCredentialsForMU(
+ pkcs.GetCredentials(userProp, "0:0")), pool.Name);
+ authCacheMap.Add(userName, mu_cache);
+ IRegion<TKey, TVal> m_region = mu_cache.GetRegion<TKey, TVal>(regionName);
+ proxyRegionMap.Add(userName, m_region);
+ Dictionary<string, int> opMAP = new Dictionary<string, int>();
+ Dictionary<string, int> expMAP = new Dictionary<string, int>();
+ operationMap[userName] = opMAP;
+ exceptionMap[userName] = expMAP;
+ Utility.GetClientProperties(gen.AuthInit, null, ref userProp);
+ FwkInfo("Security properties entries: {0}", userProp);
+ switch (i)
+ {
+ case 0:
+ case 1:
+ setAdminRole(userName);
+ break;
+ case 2:
+ case 3:
+ case 4:
+ setReaderRole(userName);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ setWriterRole(userName);
+ break;
+ case 8:
+ case 9:
+ setQueryRole(userName);
+ break;
+ };
+ }
+ }
}
public string GetKeyStoreDir(string dataDir)
diff --git a/tests/cli/NewFwkLib/NewFwkLib.csproj.in b/tests/cli/NewFwkLib/NewFwkLib.csproj.in
index 71abeff..f64d801 100644
--- a/tests/cli/NewFwkLib/NewFwkLib.csproj.in
+++ b/tests/cli/NewFwkLib/NewFwkLib.csproj.in
@@ -125,6 +125,11 @@
<Project>{5055633B-6D1C-488D-B934-1AC482C915F7}</Project>
<Name>PdxVersion2Lib</Name>
</ProjectReference>
+ <ProjectReference Include="..\PkcsWrapper\PkcsWrapper.vcxproj">
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ <Name>PkcsWrapper</Name>
+ </ProjectReference>
<ProjectReference Include="..\QueryHelper\QueryWrapper.vcxproj">
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
diff --git a/tests/cli/PkcsWrapper/CMakeLists.txt b/tests/cli/PkcsWrapper/CMakeLists.txt
new file mode 100644
index 0000000..366f185
--- /dev/null
+++ b/tests/cli/PkcsWrapper/CMakeLists.txt
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+cmake_minimum_required(VERSION 3.10)
+project(PkcsWrapper LANGUAGES CXX)
+
+add_library(PkcsWrapper SHARED
+ PkcsAuthInitMN.cpp
+ PkcsAuthInitMN.hpp
+)
+
+target_compile_options(${PROJECT_NAME}
+ PRIVATE
+ # disabled warnings
+ /wd4947
+)
+
+set_target_properties(PkcsWrapper PROPERTIES
+ VS_GLOBAL_CLRSupport "true"
+ VS_GLOBAL_KEYWORD "ManagedCProj"
+ VS_GLOBAL_PROJECT_TYPES "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
+ VS_GLOBAL_ROOTNAMESPACE "Apache.Geode.Client.Tests"
+ VS_DOTNET_REFERENCES "System;System.Xml"
+)
+
+target_link_libraries(PkcsWrapper
+ PUBLIC
+ # Apache.Geode #- Causes include of .lib
+ PRIVATE
+ c++cli
+ c++11
+ security
+)
+
+# Makes project only reference, no .lib.
+add_dependencies(PkcsWrapper Apache.Geode)
+
+include_directories(${CMAKE_SOURCE_DIR}/clicache/src)
+include_directories(${CMAKE_SOURCE_DIR}/tests/cpp/security)
+
+string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SHARED_LINKER_FLAGS_STRONG_KEY}")
+
+# For Visual Studio organization
+set_target_properties(PkcsWrapper PROPERTIES FOLDER cli/test/integration)
diff --git a/tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp b/tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp
new file mode 100644
index 0000000..86c1772
--- /dev/null
+++ b/tests/cli/PkcsWrapper/PkcsAuthInitMN.cpp
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "PkcsAuthInitMN.hpp"
+#include "begin_native.hpp"
+#include <geode/Properties.hpp>
+#include "end_native.hpp"
+
+using namespace System;
+using namespace Apache::Geode::Client::Tests;
+using namespace Apache::Geode::Client;
+
+PkcsAuthInit::PkcsAuthInit()
+{
+
+}
+
+PkcsAuthInit::~PkcsAuthInit()
+{
+
+}
+
+void PkcsAuthInit::Close()
+{
+}
+
+//generic <class TPropKey, class TPropValue>
+Apache::Geode::Client::Properties<String^, Object^>^
+PkcsAuthInit::GetCredentials(
+ Apache::Geode::Client::Properties<String^, String^> ^props, System::String ^server)
+{
+ throw gcnew System::NotImplementedException();
+}
diff --git a/tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp b/tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp
new file mode 100644
index 0000000..249863a
--- /dev/null
+++ b/tests/cli/PkcsWrapper/PkcsAuthInitMN.hpp
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 once
+
+#include <memory>
+#include "native_shared_ptr.hpp"
+#include "PkcsAuthInit.hpp"
+
+using namespace System;
+
+using namespace Apache::Geode::Client;
+
+namespace Apache
+{
+ namespace Geode
+ {
+ namespace Client
+ {
+ namespace Tests
+ {
+ public ref class PkcsAuthInit sealed
+ : public Apache::Geode::Client::IAuthInitialize
+ {
+ public:
+
+ PkcsAuthInit();
+
+ ~PkcsAuthInit();
+
+ //generic <class TPropKey, class TPropValue>
+ virtual Apache::Geode::Client::Properties<String^, Object^> ^
+ GetCredentials(
+ Apache::Geode::Client::Properties<String^, String^>^ props, String^ server);
+
+ virtual void Close();
+
+ internal:
+ PkcsAuthInit(const std::shared_ptr<apache::geode::client::PKCSAuthInitInternal>& nativeptr)
+ {
+ m_nativeptr = gcnew native_shared_ptr<apache::geode::client::PKCSAuthInitInternal>(nativeptr);
+ }
+
+ private:
+ native_shared_ptr<apache::geode::client::PKCSAuthInitInternal>^ m_nativeptr;
+ };
+ }
+ }
+ }
+}
+
diff --git a/tests/cli/SecurityUtil/CredentialGeneratorN.cs b/tests/cli/SecurityUtil/CredentialGeneratorN.cs
index 3f5185c..0471ea2 100644
--- a/tests/cli/SecurityUtil/CredentialGeneratorN.cs
+++ b/tests/cli/SecurityUtil/CredentialGeneratorN.cs
@@ -112,6 +112,8 @@ namespace Apache.Geode.Client.Tests
return null;
case ClassCode.LDAP:
return new LDAPCredentialGenerator();
+ case ClassCode.PKCS:
+ return new PKCSCredentialGenerator(isMultiUser);
case ClassCode.SSL:
// return new SSLCredentialGenerator();
return null;
diff --git a/tests/cli/SecurityUtil/SecurityUtil.csproj.in b/tests/cli/SecurityUtil/SecurityUtil.csproj.in
index a6ae959..0ecf164 100644
--- a/tests/cli/SecurityUtil/SecurityUtil.csproj.in
+++ b/tests/cli/SecurityUtil/SecurityUtil.csproj.in
@@ -110,6 +110,7 @@
<Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\CredentialGeneratorN.cs" />
<Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\DummyAuthorization3N.cs" />
<Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\LdapCredentialGeneratorN.cs" />
+ <Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\PKCSCredentialGeneratorN.cs" />
<Compile Include="$(CMAKE_CURRENT_SOURCE_DIR)\SecurityUtil\XmlAuthzCredentialGeneratorN.cs" />
</ItemGroup>
<ItemGroup>
@@ -117,6 +118,10 @@
<Project>{796727E8-3A6A-46BE-A2DB-584A4774CD51}</Project>
<Name>DUnitFramework</Name>
</ProjectReference>
+ <ProjectReference Include="..\PkcsWrapper\PkcsWrapper.vcxproj">
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
diff --git a/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs b/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs
index 29b1f7f..e10160a 100644
--- a/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs
+++ b/tests/cli/SecurityUtil/XmlAuthzCredentialGeneratorN.cs
@@ -143,6 +143,8 @@ namespace Apache.Geode.Client.Tests
return GetDummyPrincipal(roleType, index);
case CredentialGenerator.ClassCode.LDAP:
return GetLdapPrincipal(roleType, index);
+ case CredentialGenerator.ClassCode.PKCS:
+ return GetPKCSPrincipal(roleType, index);
}
return null;
}
@@ -174,6 +176,8 @@ namespace Apache.Geode.Client.Tests
return GetDummyPrincipal(disallowedRoleType, index);
case CredentialGenerator.ClassCode.LDAP:
return GetLdapPrincipal(disallowedRoleType, index);
+ case CredentialGenerator.ClassCode.PKCS:
+ return GetPKCSPrincipal(disallowedRoleType, index);
}
return null;
}
@@ -208,6 +212,14 @@ namespace Apache.Geode.Client.Tests
return GetUserPrincipal(GetLdapUser(roleType, index));
}
+ private Properties<string, string> GetPKCSPrincipal(Role roleType, int index)
+ {
+ string userName = GetLdapUser(roleType, index);
+ Properties<string, string> props = new Properties<string, string>();
+ props.Insert(PKCSCredentialGenerator.KeyStoreAliasProp, userName);
+ return props;
+ }
+
private string GetLdapUser(Role roleType, int index)
{
const string userPrefix = "geode";
diff --git a/tests/cpp/security/CMakeLists.txt b/tests/cpp/security/CMakeLists.txt
index 8396cc2..cee20a6 100644
--- a/tests/cpp/security/CMakeLists.txt
+++ b/tests/cpp/security/CMakeLists.txt
@@ -24,6 +24,8 @@ add_library(security STATIC
DummyCredentialGenerator3.hpp
LdapUserCredentialGenerator.hpp
NoopCredentialGenerator.hpp
+ PkcsAuthInit.cpp
+ PkcsAuthInit.hpp
PkcsCredentialGenerator.hpp
typedefs.hpp
XmlAuthzCredentialGenerator.hpp
diff --git a/tests/cpp/security/PkcsAuthInit.cpp b/tests/cpp/security/PkcsAuthInit.cpp
new file mode 100644
index 0000000..9f75914
--- /dev/null
+++ b/tests/cpp/security/PkcsAuthInit.cpp
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "PkcsAuthInit.hpp"
+
+#include <openssl-compat.h>
+
+#include <cstdio>
+#include <string>
+#include <util/Log.hpp>
+
+#include <geode/CacheableBuiltins.hpp>
+#include <geode/ExceptionTypes.hpp>
+#include <geode/Properties.hpp>
+
+#include "SerializationRegistry.hpp"
+#include "security_export.h"
+
+namespace apache {
+namespace geode {
+namespace client {
+std::shared_ptr<CacheableString> convertBytesToString(const uint8_t* bytes,
+ int32_t length,
+ size_t maxLength) {
+ if (bytes) {
+ std::string str;
+ size_t totalBytes = 0;
+ char byteStr[20];
+ for (int32_t index = 0; index < length; ++index) {
+ int len = sprintf(byteStr, "%d ", bytes[index]);
+ totalBytes += len;
+ // no use going beyond maxLength since LOG* methods will truncate
+ // in any case
+ if (maxLength > 0 && totalBytes > maxLength) {
+ break;
+ }
+ str.append(byteStr, len);
+ }
+ return CacheableString::create(str);
+ }
+ return CacheableString::create("");
+}
+
+extern "C" {
+SECURITY_EXPORT AuthInitialize* createPKCSAuthInitInstance() {
+ return new PKCSAuthInitInternal();
+}
+
+uint8_t* createSignature(EVP_PKEY* key, X509* cert,
+ const unsigned char* inputBuffer,
+ uint32_t inputBufferLen, unsigned int* signatureLen) {
+ if (!key || !cert || !inputBuffer) {
+ return nullptr;
+ }
+ const ASN1_OBJECT* macobj;
+ const X509_ALGOR* algorithm = nullptr;
+ X509_ALGOR_get0(&macobj, nullptr, nullptr, algorithm);
+ const EVP_MD* signatureDigest = EVP_get_digestbyobj(macobj);
+ EVP_MD_CTX* signatureCtx = EVP_MD_CTX_new();
+ auto signatureData =
+ std::unique_ptr<uint8_t[]>(new uint8_t[EVP_PKEY_size(key)]);
+ bool result =
+ (EVP_SignInit_ex(signatureCtx, signatureDigest, nullptr) &&
+ EVP_SignUpdate(signatureCtx, inputBuffer, inputBufferLen) &&
+ EVP_SignFinal(signatureCtx, signatureData.get(), signatureLen, key));
+ EVP_MD_CTX_free(signatureCtx);
+ if (result) {
+ return signatureData.release();
+ }
+ return nullptr;
+}
+
+bool readPKCSPublicPrivateKey(FILE* keyStoreFP, const char* keyStorePassword,
+ EVP_PKEY** outPrivateKey, X509** outCertificate) {
+ PKCS12* p12;
+
+ if (!keyStoreFP || !keyStorePassword || (keyStorePassword[0] == '\0')) {
+ return (false);
+ }
+
+ p12 = d2i_PKCS12_fp(keyStoreFP, nullptr);
+
+ if (!p12) {
+ return (false);
+ }
+
+ if (!PKCS12_parse(p12, keyStorePassword, outPrivateKey, outCertificate,
+ nullptr)) {
+ return (false);
+ }
+
+ PKCS12_free(p12);
+
+ return (outPrivateKey && outCertificate);
+}
+
+bool openSSLInit() {
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ return true;
+}
+
+static bool s_initDone = openSSLInit();
+}
+// end of extern "C"
+std::shared_ptr<Properties> PKCSAuthInitInternal::getCredentials(
+ const std::shared_ptr<Properties>& securityprops, const std::string&) {
+ if (!s_initDone) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "OpenSSL initialization failed.");
+ }
+ if (securityprops == nullptr || securityprops->getSize() <= 0) {
+ throw AuthenticationRequiredException(
+ "PKCSAuthInit::getCredentials: "
+ "No security-* properties are set.");
+ }
+
+ auto keyStoreptr = securityprops->find(KEYSTORE_FILE_PATH1);
+
+ const char* keyStorePath = keyStoreptr->value().c_str();
+
+ if (!keyStorePath) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "key-store file path property KEYSTORE_FILE_PATH not set.");
+ }
+
+ auto aliasptr = securityprops->find(KEYSTORE_ALIAS1);
+
+ const char* alias = aliasptr->value().c_str();
+
+ if (!alias) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "key-store alias property KEYSTORE_ALIAS not set.");
+ }
+
+ auto keyStorePassptr = securityprops->find(KEYSTORE_PASSWORD1);
+
+ const char* keyStorePass = keyStorePassptr->value().c_str();
+
+ if (!keyStorePass) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "key-store password property KEYSTORE_PASSWORD not set.");
+ }
+
+ FILE* keyStoreFP = fopen(keyStorePath, "r");
+ if (!keyStoreFP) {
+ char msg[1024];
+ sprintf(msg, "PKCSAuthInit::getCredentials: Unable to open keystore %s",
+ keyStorePath);
+ throw AuthenticationFailedException(msg);
+ }
+
+ EVP_PKEY* privateKey = nullptr;
+ X509* cert = nullptr;
+
+ /* Read the Public and Private Key from keystore in file */
+ if (!readPKCSPublicPrivateKey(keyStoreFP, keyStorePass, &privateKey, &cert)) {
+ fclose(keyStoreFP);
+ char msg[1024];
+ sprintf(msg,
+ "PKCSAuthInit::getCredentials: Unable to read PKCS "
+ "public key from %s",
+ keyStorePath);
+ throw AuthenticationFailedException(msg);
+ }
+
+ fclose(keyStoreFP);
+ unsigned int lengthEncryptedData = 0;
+
+ auto signatureData = std::unique_ptr<uint8_t[]>(createSignature(
+ privateKey, cert, reinterpret_cast<const unsigned char*>(alias),
+ static_cast<uint32_t>(strlen(alias)), &lengthEncryptedData));
+ EVP_PKEY_free(privateKey);
+ X509_free(cert);
+ if (!signatureData) {
+ throw AuthenticationFailedException(
+ "PKCSAuthInit::getCredentials: "
+ "Unable to create signature");
+ }
+ std::shared_ptr<Cacheable> signatureValPtr;
+ if (m_stringCredentials) {
+ // convert signature bytes to base64
+ signatureValPtr =
+ convertBytesToString(signatureData.get(), lengthEncryptedData, 2048);
+ LOGINFO(" Converting CREDS to STRING: %s",
+ signatureValPtr->toString().c_str());
+ } else {
+ signatureValPtr = CacheableBytes::create(std::vector<int8_t>(
+ signatureData.get(), signatureData.get() + lengthEncryptedData));
+ LOGINFO(" Converting CREDS to BYTES: %s",
+ signatureValPtr->toString().c_str());
+ }
+ auto credentials = Properties::create();
+ credentials->insert(KEYSTORE_ALIAS1, alias);
+ credentials->insert(CacheableString::create(SIGNATURE_DATA1),
+ signatureValPtr);
+ return credentials;
+}
+} // namespace client
+} // namespace geode
+} // namespace apache
diff --git a/tests/cpp/security/PkcsAuthInit.hpp b/tests/cpp/security/PkcsAuthInit.hpp
new file mode 100644
index 0000000..3eb03da
--- /dev/null
+++ b/tests/cpp/security/PkcsAuthInit.hpp
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 once
+
+#ifndef GEODE_SECURITY_PKCSAUTHINIT_H_
+#define GEODE_SECURITY_PKCSAUTHINIT_H_
+
+#include <cstdio>
+#include <cstdlib>
+
+#pragma error_messages(off, macroredef)
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#pragma error_messages(on, macroredef)
+
+#include <geode/AuthInitialize.hpp>
+
+/**
+ * @file
+ */
+const char KEYSTORE_FILE_PATH1[] = "security-keystorepath";
+
+const char KEYSTORE_ALIAS1[] = "security-alias";
+
+const char KEYSTORE_PASSWORD1[] = "security-keystorepass";
+
+const char SIGNATURE_DATA1[] = "security-signature";
+
+namespace apache {
+namespace geode {
+namespace client {
+
+/**
+ * @class PKCSAuthInit Implementation PKCSAuthInit.hpp
+ * PKCSAuthInit API for getCredentials.
+ * The PKCSAuthInit class derives from AuthInitialize base class.
+ * It uses the provided alias, password and corresponding keystore to obtain the
+ * private key and
+ * encrypts data. This data is sent to server for authentication.
+ *
+ */
+
+class PKCSAuthInitInternal : public AuthInitialize {
+ public:
+ explicit PKCSAuthInitInternal(bool makeString = false)
+ : m_stringCredentials(makeString) {}
+ ~PKCSAuthInitInternal() noexcept override = default;
+
+ /**@brief initialize with the given set of security properties
+ * and return the credentials for the client as properties.
+ * @param props the set of security properties provided to the
+ * <code>DistributedSystem.connect</code> method
+ * @param server it is the ID of the current endpoint.
+ * The format expected is "host:port".
+ * @returns the credentials to be used for the given <code>server</code>
+ */
+ std::shared_ptr<Properties> getCredentials(
+ const std::shared_ptr<Properties>& securityprops,
+ const std::string& server) override;
+
+ /**
+ * @brief Invoked before the cache goes down.
+ */
+ void close() override { return; }
+
+ /**
+ * @brief private members
+ */
+
+ private:
+ bool m_stringCredentials;
+};
+} // namespace client
+} // namespace geode
+} // namespace apache
+
+#endif // GEODE_SECURITY_PKCSAUTHINIT_H_