123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ############################################################################## */
- #include "jliball.hpp"
- #if defined(_USE_OPENSSL) && !defined(_WIN32)
- #include <openssl/pem.h>
- #include <openssl/err.h>
- #include <openssl/evp.h>
- #endif
- #include "jencrypt.hpp"
- #include "digisign.hpp"
- #include <mutex>
- namespace cryptohelper
- {
- #if defined(_USE_OPENSSL) && !defined(_WIN32)
- //Create base 64 encoded digital signature of given data
- bool digiSign(StringBuffer &b64Signature, size32_t dataSz, const void *data, const CLoadedKey &signingKey)
- {
- OwnedEVPMdCtx signingCtx(EVP_MD_CTX_create());
- //initialize context for SHA-256 hashing function
- int rc = EVP_DigestSignInit(signingCtx, nullptr, EVP_sha256(), nullptr, signingKey);
- if (rc <= 0)
- throwEVPException(-1, "digiSign:EVP_DigestSignInit");
- //add string to the context
- if (EVP_DigestSignUpdate(signingCtx, data, dataSz) <= 0)
- throwEVPException(-1, "digiSign:EVP_DigestSignUpdate");
- //compute length of signature
- size_t encMsgLen;
- if (EVP_DigestSignFinal(signingCtx, nullptr, &encMsgLen) <= 0)
- throwEVPException(-1, "digiSign:EVP_DigestSignFinal1");
- if (encMsgLen == 0)
- throwEVPException(-1, "digiSign:EVP_DigestSignFinal length returned 0");
- //compute signature (signed digest)
- OwnedEVPMemory encMsg = OPENSSL_malloc(encMsgLen);
- if (encMsg == nullptr)
- throw MakeStringException(-1, "digiSign:OPENSSL_malloc(%u) returned NULL", (unsigned)encMsgLen);
- if (EVP_DigestSignFinal(signingCtx, (unsigned char *)encMsg.get(), &encMsgLen) <= 0)
- throwEVPException(-1, "digiSign:EVP_DigestSignFinal2");
- //convert to base64
- JBASE64_Encode(encMsg, encMsgLen, b64Signature, false);
- return true;
- }
- //Verify the given data was used to create the given digital signature
- bool digiVerify(const char *b64Signature, size32_t dataSz, const void *data, const CLoadedKey &verifyingKey)
- {
- OwnedEVPMdCtx verifyingCtx(EVP_MD_CTX_create());
- int rc = EVP_DigestVerifyInit(verifyingCtx, nullptr, EVP_sha256(), nullptr, verifyingKey);
- if (rc <= 0)
- throwEVPException(-1, "digiVerify:EVP_DigestVerifyInit");
- //decode base64 signature
- StringBuffer decodedSig;
- JBASE64_Decode(b64Signature, decodedSig);
- if (EVP_DigestVerifyUpdate(verifyingCtx, data, dataSz) <= 0)
- throwEVPException(-1, "digiVerify:EVP_DigestVerifyUpdate");
- return 1 == EVP_DigestVerifyFinal(verifyingCtx, (unsigned char *)decodedSig.str(), decodedSig.length());
- }
- class CDigitalSignatureManager : public CSimpleInterfaceOf<IDigitalSignatureManager>
- {
- private:
- Linked<CLoadedKey> pubKey, privKey;
- bool signingConfigured = false;
- bool verifyingConfigured = false;
- public:
- CDigitalSignatureManager(CLoadedKey *_pubKey, CLoadedKey *_privKey) : pubKey(_pubKey), privKey(_privKey)
- {
- signingConfigured = nullptr != privKey.get();
- verifyingConfigured = nullptr != pubKey.get();
- }
- virtual bool isDigiSignerConfigured() const override
- {
- return signingConfigured;
- }
- virtual bool isDigiVerifierConfigured() const override
- {
- return verifyingConfigured;
- }
- //Create base 64 encoded digital signature of given data
- virtual bool digiSign(StringBuffer & b64Signature, size32_t dataSz, const void *data) const override
- {
- if (!signingConfigured)
- throw MakeStringException(-1, "digiSign:Creating Digital Signatures not configured");
- return cryptohelper::digiSign(b64Signature, dataSz, data, *privKey);
- }
- virtual bool digiSign(StringBuffer & b64Signature, const char *text) const override
- {
- return digiSign(b64Signature, strlen(text), text);
- }
- //Verify the given data was used to create the given digital signature
- virtual bool digiVerify(const char *b64Signature, size32_t dataSz, const void *data) const override
- {
- if (!verifyingConfigured)
- throw MakeStringException(-1, "digiVerify:Verifying Digital Signatures not configured");
- return cryptohelper::digiVerify(b64Signature, dataSz, data, *pubKey);
- }
- virtual bool digiVerify(const char *b64Signature, const char *text) const override
- {
- return digiVerify(b64Signature, strlen(text), text);
- }
- };
- #else
- //Dummy implementation if no OPENSSL available.
- bool digiSign(StringBuffer &b64Signature, const char *text, const CLoadedKey &signingKey)
- {
- throwStringExceptionV(-1, "digiSign: unavailable without openssl");
- }
- bool digiVerify(const char *b64Signature, const char *text, const CLoadedKey &verifyingKey)
- {
- throwStringExceptionV(-1, "digiVerify: unavailable without openssl");
- }
- class CDigitalSignatureManager : public CSimpleInterfaceOf<IDigitalSignatureManager>
- {
- public:
- CDigitalSignatureManager(const char * _pubKeyBuff, const char * _privKeyBuff, const char * _passPhrase)
- {
- WARNLOG("CDigitalSignatureManager: Platform built without OPENSSL!");
- }
- virtual bool isDigiSignerConfigured() const override
- {
- return false;
- }
- virtual bool isDigiVerifierConfigured() const override
- {
- return false;
- }
- virtual bool digiSign(StringBuffer & b64Signature, size32_t dataSz, const void *data) const override
- {
- throwStringExceptionV(-1, "digiSign: unavailable without openssl");
- }
- virtual bool digiSign(StringBuffer & b64Signature, const char * text) const override
- {
- throwStringExceptionV(-1, "digiSign: unavailable without openssl");
- }
- virtual bool digiVerify(const char *b64Signature, const char * text) const override
- {
- throwStringExceptionV(-1, "digiVerify: unavailable without openssl");
- }
- virtual bool digiVerify(const char *b64Signature, size32_t dataSz, const void *data) const override
- {
- throwStringExceptionV(-1, "digiVerify: unavailable without openssl");
- }
- };
- #endif
- static IDigitalSignatureManager * dsm = nullptr;
- static std::once_flag dsmInitFlag;
- MODULE_INIT(INIT_PRIORITY_STANDARD)
- {
- return true;
- }
- MODULE_EXIT()
- {
- ::Release(dsm);
- }
- static void createDigitalSignatureManagerInstance(IDigitalSignatureManager * * ppDSM)
- {
- const char * pubKey = nullptr, *privKey = nullptr, *passPhrase = nullptr;
- queryHPCCPKIKeyFiles(nullptr, &pubKey, &privKey, &passPhrase);
- *ppDSM = createDigitalSignatureManagerInstanceFromFiles(pubKey, privKey, passPhrase);
- }
- //Returns reference to singleton instance created from environment.conf key file settings
- IDigitalSignatureManager * queryDigitalSignatureManagerInstanceFromEnv()
- {
- #if defined(_USE_OPENSSL) && !defined(_WIN32)
- std::call_once(dsmInitFlag, createDigitalSignatureManagerInstance, &dsm);
- return dsm;
- #else
- return nullptr;
- #endif
- }
- //Create using given key filespecs
- //Caller must release when no longer needed
- IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromFiles(const char * pubKeyFileName, const char *privKeyFileName, const char * passPhrase)
- {
- #if defined(_USE_OPENSSL) && !defined(_WIN32)
- Owned<CLoadedKey> pubKey, privKey;
- Owned<IMultiException> exceptions;
- if (!isEmptyString(pubKeyFileName))
- {
- try
- {
- pubKey.setown(loadPublicKeyFromFile(pubKeyFileName, passPhrase));
- }
- catch (IException * e)
- {
- if (!exceptions)
- exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromFiles"));
- exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load public key file"));
- e->Release();
- }
- }
- if (!isEmptyString(privKeyFileName))
- {
- try
- {
- privKey.setown(loadPrivateKeyFromFile(privKeyFileName, passPhrase));
- }
- catch (IException * e)
- {
- if (!exceptions)
- exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromFiles"));
- exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load private key file"));
- e->Release();
- }
- }
- // NB: allow it continue if 1 of the keys successfully loaded.
- if (exceptions && exceptions->ordinality())
- {
- if (!pubKey && !privKey)
- throw exceptions.getClear();
- else
- EXCLOG(exceptions, nullptr);
- }
- return new CDigitalSignatureManager(pubKey, privKey);
- #else
- return nullptr;
- #endif
- }
- //Create using given PEM formatted keys
- //Caller must release when no longer needed
- IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromKeys(const char * pubKeyString, const char * privKeyString, const char * passPhrase)
- {
- #if defined(_USE_OPENSSL) && !defined(_WIN32)
- Owned<CLoadedKey> pubKey, privKey;
- Owned<IMultiException> exceptions;
- if (!isEmptyString(pubKeyString))
- {
- try
- {
- pubKey.setown(loadPublicKeyFromMemory(pubKeyString, passPhrase));
- }
- catch (IException * e)
- {
- if (!exceptions)
- exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromKeys"));
- exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load public key"));
- e->Release();
- }
- }
- if (!isEmptyString(privKeyString))
- {
- try
- {
- privKey.setown(loadPrivateKeyFromMemory(privKeyString, passPhrase));
- }
- catch (IException * e)
- {
- if (!exceptions)
- exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromKeys"));
- exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load private key"));
- e->Release();
- }
- }
- // NB: allow it continue if 1 of the keys successfully loaded.
- if (exceptions && exceptions->ordinality())
- {
- if (!pubKey && !privKey)
- throw exceptions.getClear();
- else
- EXCLOG(exceptions, nullptr);
- }
- return new CDigitalSignatureManager(pubKey, privKey);
- #else
- return nullptr;
- #endif
- }
- //Create using preloaded keys
- //Caller must release when no longer needed
- IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromKeys(CLoadedKey *pubKey, CLoadedKey *privKey)
- {
- #if defined(_USE_OPENSSL) && !defined(_WIN32)
- return new CDigitalSignatureManager(pubKey, privKey);
- #else
- return nullptr;
- #endif
- }
- } // namespace cryptohelper
|