digisign.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "jliball.hpp"
  14. #if defined(_USE_OPENSSL) && !defined(_WIN32)
  15. #include <openssl/pem.h>
  16. #include <openssl/err.h>
  17. #include <openssl/evp.h>
  18. #endif
  19. #include "jencrypt.hpp"
  20. #include "digisign.hpp"
  21. #include <mutex>
  22. namespace cryptohelper
  23. {
  24. #if defined(_USE_OPENSSL) && !defined(_WIN32)
  25. //Create base 64 encoded digital signature of given data
  26. bool digiSign(StringBuffer &b64Signature, size32_t dataSz, const void *data, const CLoadedKey &signingKey)
  27. {
  28. OwnedEVPMdCtx signingCtx(EVP_MD_CTX_create());
  29. //initialize context for SHA-256 hashing function
  30. int rc = EVP_DigestSignInit(signingCtx, nullptr, EVP_sha256(), nullptr, signingKey);
  31. if (rc <= 0)
  32. throwEVPException(-1, "digiSign:EVP_DigestSignInit");
  33. //add string to the context
  34. if (EVP_DigestSignUpdate(signingCtx, data, dataSz) <= 0)
  35. throwEVPException(-1, "digiSign:EVP_DigestSignUpdate");
  36. //compute length of signature
  37. size_t encMsgLen;
  38. if (EVP_DigestSignFinal(signingCtx, nullptr, &encMsgLen) <= 0)
  39. throwEVPException(-1, "digiSign:EVP_DigestSignFinal1");
  40. if (encMsgLen == 0)
  41. throwEVPException(-1, "digiSign:EVP_DigestSignFinal length returned 0");
  42. //compute signature (signed digest)
  43. OwnedEVPMemory encMsg = OPENSSL_malloc(encMsgLen);
  44. if (encMsg == nullptr)
  45. throw MakeStringException(-1, "digiSign:OPENSSL_malloc(%u) returned NULL", (unsigned)encMsgLen);
  46. if (EVP_DigestSignFinal(signingCtx, (unsigned char *)encMsg.get(), &encMsgLen) <= 0)
  47. throwEVPException(-1, "digiSign:EVP_DigestSignFinal2");
  48. //convert to base64
  49. JBASE64_Encode(encMsg, encMsgLen, b64Signature, false);
  50. return true;
  51. }
  52. //Verify the given data was used to create the given digital signature
  53. bool digiVerify(const char *b64Signature, size32_t dataSz, const void *data, const CLoadedKey &verifyingKey)
  54. {
  55. OwnedEVPMdCtx verifyingCtx(EVP_MD_CTX_create());
  56. int rc = EVP_DigestVerifyInit(verifyingCtx, nullptr, EVP_sha256(), nullptr, verifyingKey);
  57. if (rc <= 0)
  58. throwEVPException(-1, "digiVerify:EVP_DigestVerifyInit");
  59. //decode base64 signature
  60. StringBuffer decodedSig;
  61. JBASE64_Decode(b64Signature, decodedSig);
  62. if (EVP_DigestVerifyUpdate(verifyingCtx, data, dataSz) <= 0)
  63. throwEVPException(-1, "digiVerify:EVP_DigestVerifyUpdate");
  64. return 1 == EVP_DigestVerifyFinal(verifyingCtx, (unsigned char *)decodedSig.str(), decodedSig.length());
  65. }
  66. class CDigitalSignatureManager : public CSimpleInterfaceOf<IDigitalSignatureManager>
  67. {
  68. private:
  69. Linked<CLoadedKey> pubKey, privKey;
  70. bool signingConfigured = false;
  71. bool verifyingConfigured = false;
  72. public:
  73. CDigitalSignatureManager(CLoadedKey *_pubKey, CLoadedKey *_privKey) : pubKey(_pubKey), privKey(_privKey)
  74. {
  75. signingConfigured = nullptr != privKey.get();
  76. verifyingConfigured = nullptr != pubKey.get();
  77. }
  78. virtual bool isDigiSignerConfigured() const override
  79. {
  80. return signingConfigured;
  81. }
  82. virtual bool isDigiVerifierConfigured() const override
  83. {
  84. return verifyingConfigured;
  85. }
  86. //Create base 64 encoded digital signature of given data
  87. virtual bool digiSign(StringBuffer & b64Signature, size32_t dataSz, const void *data) const override
  88. {
  89. if (!signingConfigured)
  90. throw MakeStringException(-1, "digiSign:Creating Digital Signatures not configured");
  91. return cryptohelper::digiSign(b64Signature, dataSz, data, *privKey);
  92. }
  93. virtual bool digiSign(StringBuffer & b64Signature, const char *text) const override
  94. {
  95. return digiSign(b64Signature, strlen(text), text);
  96. }
  97. //Verify the given data was used to create the given digital signature
  98. virtual bool digiVerify(const char *b64Signature, size32_t dataSz, const void *data) const override
  99. {
  100. if (!verifyingConfigured)
  101. throw MakeStringException(-1, "digiVerify:Verifying Digital Signatures not configured");
  102. return cryptohelper::digiVerify(b64Signature, dataSz, data, *pubKey);
  103. }
  104. virtual bool digiVerify(const char *b64Signature, const char *text) const override
  105. {
  106. return digiVerify(b64Signature, strlen(text), text);
  107. }
  108. };
  109. #else
  110. //Dummy implementation if no OPENSSL available.
  111. bool digiSign(StringBuffer &b64Signature, const char *text, const CLoadedKey &signingKey)
  112. {
  113. throwStringExceptionV(-1, "digiSign: unavailable without openssl");
  114. }
  115. bool digiVerify(const char *b64Signature, const char *text, const CLoadedKey &verifyingKey)
  116. {
  117. throwStringExceptionV(-1, "digiVerify: unavailable without openssl");
  118. }
  119. class CDigitalSignatureManager : public CSimpleInterfaceOf<IDigitalSignatureManager>
  120. {
  121. public:
  122. CDigitalSignatureManager(const char * _pubKeyBuff, const char * _privKeyBuff, const char * _passPhrase)
  123. {
  124. WARNLOG("CDigitalSignatureManager: Platform built without OPENSSL!");
  125. }
  126. virtual bool isDigiSignerConfigured() const override
  127. {
  128. return false;
  129. }
  130. virtual bool isDigiVerifierConfigured() const override
  131. {
  132. return false;
  133. }
  134. virtual bool digiSign(StringBuffer & b64Signature, size32_t dataSz, const void *data) const override
  135. {
  136. throwStringExceptionV(-1, "digiSign: unavailable without openssl");
  137. }
  138. virtual bool digiSign(StringBuffer & b64Signature, const char * text) const override
  139. {
  140. throwStringExceptionV(-1, "digiSign: unavailable without openssl");
  141. }
  142. virtual bool digiVerify(const char *b64Signature, const char * text) const override
  143. {
  144. throwStringExceptionV(-1, "digiVerify: unavailable without openssl");
  145. }
  146. virtual bool digiVerify(const char *b64Signature, size32_t dataSz, const void *data) const override
  147. {
  148. throwStringExceptionV(-1, "digiVerify: unavailable without openssl");
  149. }
  150. };
  151. #endif
  152. static IDigitalSignatureManager * dsm = nullptr;
  153. static std::once_flag dsmInitFlag;
  154. MODULE_INIT(INIT_PRIORITY_STANDARD)
  155. {
  156. return true;
  157. }
  158. MODULE_EXIT()
  159. {
  160. ::Release(dsm);
  161. }
  162. static void createDigitalSignatureManagerInstance(IDigitalSignatureManager * * ppDSM)
  163. {
  164. const char * pubKey = nullptr, *privKey = nullptr, *passPhrase = nullptr;
  165. queryHPCCPKIKeyFiles(nullptr, &pubKey, &privKey, &passPhrase);
  166. *ppDSM = createDigitalSignatureManagerInstanceFromFiles(pubKey, privKey, passPhrase);
  167. }
  168. //Returns reference to singleton instance created from environment.conf key file settings
  169. IDigitalSignatureManager * queryDigitalSignatureManagerInstanceFromEnv()
  170. {
  171. #if defined(_USE_OPENSSL) && !defined(_WIN32)
  172. std::call_once(dsmInitFlag, createDigitalSignatureManagerInstance, &dsm);
  173. return dsm;
  174. #else
  175. return nullptr;
  176. #endif
  177. }
  178. //Create using given key filespecs
  179. //Caller must release when no longer needed
  180. IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromFiles(const char * pubKeyFileName, const char *privKeyFileName, const char * passPhrase)
  181. {
  182. #if defined(_USE_OPENSSL) && !defined(_WIN32)
  183. Owned<CLoadedKey> pubKey, privKey;
  184. Owned<IMultiException> exceptions;
  185. if (!isEmptyString(pubKeyFileName))
  186. {
  187. try
  188. {
  189. pubKey.setown(loadPublicKeyFromFile(pubKeyFileName, passPhrase));
  190. }
  191. catch (IException * e)
  192. {
  193. if (!exceptions)
  194. exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromFiles"));
  195. exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load public key file"));
  196. e->Release();
  197. }
  198. }
  199. if (!isEmptyString(privKeyFileName))
  200. {
  201. try
  202. {
  203. privKey.setown(loadPrivateKeyFromFile(privKeyFileName, passPhrase));
  204. }
  205. catch (IException * e)
  206. {
  207. if (!exceptions)
  208. exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromFiles"));
  209. exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load private key file"));
  210. e->Release();
  211. }
  212. }
  213. // NB: allow it continue if 1 of the keys successfully loaded.
  214. if (exceptions && exceptions->ordinality())
  215. {
  216. if (!pubKey && !privKey)
  217. throw exceptions.getClear();
  218. else
  219. EXCLOG(exceptions, nullptr);
  220. }
  221. return new CDigitalSignatureManager(pubKey, privKey);
  222. #else
  223. return nullptr;
  224. #endif
  225. }
  226. //Create using given PEM formatted keys
  227. //Caller must release when no longer needed
  228. IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromKeys(const char * pubKeyString, const char * privKeyString, const char * passPhrase)
  229. {
  230. #if defined(_USE_OPENSSL) && !defined(_WIN32)
  231. Owned<CLoadedKey> pubKey, privKey;
  232. Owned<IMultiException> exceptions;
  233. if (!isEmptyString(pubKeyString))
  234. {
  235. try
  236. {
  237. pubKey.setown(loadPublicKeyFromMemory(pubKeyString, passPhrase));
  238. }
  239. catch (IException * e)
  240. {
  241. if (!exceptions)
  242. exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromKeys"));
  243. exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load public key"));
  244. e->Release();
  245. }
  246. }
  247. if (!isEmptyString(privKeyString))
  248. {
  249. try
  250. {
  251. privKey.setown(loadPrivateKeyFromMemory(privKeyString, passPhrase));
  252. }
  253. catch (IException * e)
  254. {
  255. if (!exceptions)
  256. exceptions.setown(makeMultiException("createDigitalSignatureManagerInstanceFromKeys"));
  257. exceptions->append(* makeWrappedExceptionV(e, -1, "createDigitalSignatureManagerInstanceFromFiles:Cannot load private key"));
  258. e->Release();
  259. }
  260. }
  261. // NB: allow it continue if 1 of the keys successfully loaded.
  262. if (exceptions && exceptions->ordinality())
  263. {
  264. if (!pubKey && !privKey)
  265. throw exceptions.getClear();
  266. else
  267. EXCLOG(exceptions, nullptr);
  268. }
  269. return new CDigitalSignatureManager(pubKey, privKey);
  270. #else
  271. return nullptr;
  272. #endif
  273. }
  274. //Create using preloaded keys
  275. //Caller must release when no longer needed
  276. IDigitalSignatureManager * createDigitalSignatureManagerInstanceFromKeys(CLoadedKey *pubKey, CLoadedKey *privKey)
  277. {
  278. #if defined(_USE_OPENSSL) && !defined(_WIN32)
  279. return new CDigitalSignatureManager(pubKey, privKey);
  280. #else
  281. return nullptr;
  282. #endif
  283. }
  284. } // namespace cryptohelper