CryptKeyHolder.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * PROGRAM: Firebird samples.
  3. * MODULE: CryptKeyHolder.cpp
  4. * DESCRIPTION: Sample of how key holder may be written.
  5. *
  6. * The contents of this file are subject to the Initial
  7. * Developer's Public License Version 1.0 (the "License");
  8. * you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
  11. *
  12. * Software distributed under the License is distributed AS IS,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing rights
  15. * and limitations under the License.
  16. *
  17. * The Original Code was created by Alex Peshkov
  18. * for the Firebird Open Source RDBMS project.
  19. *
  20. * Copyright (c) 2012 Alex Peshkov <peshkoff at mail.ru>
  21. * and all contributors signed below.
  22. *
  23. * All Rights Reserved.
  24. * Contributor(s): ______________________________________.
  25. */
  26. #include "../interfaces/ifaceExamples.h"
  27. #include <atomic>
  28. namespace
  29. {
  30. IMaster* master = NULL;
  31. class PluginModule : public IPluginModuleImpl<PluginModule, CheckStatusWrapper>
  32. {
  33. public:
  34. PluginModule()
  35. : pluginManager(NULL)
  36. { }
  37. ~PluginModule()
  38. {
  39. if (pluginManager)
  40. {
  41. pluginManager->unregisterModule(this);
  42. doClean();
  43. }
  44. }
  45. void registerMe(IPluginManager* m)
  46. {
  47. pluginManager = m;
  48. pluginManager->registerModule(this);
  49. }
  50. void doClean()
  51. {
  52. pluginManager = NULL;
  53. }
  54. void threadDetach() {}
  55. private:
  56. IPluginManager* pluginManager;
  57. };
  58. class CryptKeyHolder : public IKeyHolderPluginImpl<CryptKeyHolder, CheckStatusWrapper>
  59. {
  60. public:
  61. explicit CryptKeyHolder(IPluginConfig* cnf) noexcept
  62. : callbackInterface(this), named(NULL), tempStatus(master->getStatus()),
  63. config(cnf), key(0), init(false), owner(NULL)
  64. {
  65. config->addRef();
  66. }
  67. ~CryptKeyHolder()
  68. {
  69. config->release();
  70. tempStatus.dispose();
  71. }
  72. // IKeyHolderPlugin implementation
  73. int keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback);
  74. ICryptKeyCallback* keyHandle(CheckStatusWrapper* status, const char* keyName);
  75. ICryptKeyCallback* chainHandle(CheckStatusWrapper* status);
  76. int release()
  77. {
  78. if (--refCounter == 0)
  79. {
  80. delete this;
  81. return 0;
  82. }
  83. return 1;
  84. }
  85. void addRef()
  86. {
  87. ++refCounter;
  88. }
  89. void setOwner(Firebird::IReferenceCounted* o)
  90. {
  91. owner = o;
  92. }
  93. IReferenceCounted* getOwner()
  94. {
  95. return owner;
  96. }
  97. const ISC_UCHAR& getKey()
  98. {
  99. if (!init)
  100. {
  101. keyCallback(&tempStatus, NULL);
  102. init = true;
  103. }
  104. return key;
  105. }
  106. FB_BOOLEAN useOnlyOwnKeys(CheckStatusWrapper* status)
  107. {
  108. IConfigEntry* e = getEntry(status, "OnlyOwnKey");
  109. if (!e)
  110. return FB_TRUE; // safe default
  111. FB_BOOLEAN rc = e->getBoolValue();
  112. e->release();
  113. return rc;
  114. }
  115. private:
  116. class CallbackInterface : public ICryptKeyCallbackImpl<CallbackInterface, CheckStatusWrapper>
  117. {
  118. public:
  119. explicit CallbackInterface(CryptKeyHolder* p)
  120. : holder(p)
  121. { }
  122. unsigned int callback(unsigned int, const void*, unsigned int length, void* buffer) override
  123. {
  124. const ISC_UCHAR& k = holder->getKey();
  125. if (!k)
  126. {
  127. return 0;
  128. }
  129. if (length > 0 && buffer)
  130. {
  131. memcpy(buffer, &k, 1);
  132. }
  133. return 1;
  134. }
  135. int getHashLength(Firebird::CheckStatusWrapper* status) override
  136. {
  137. const ISC_UCHAR& k = holder->getKey();
  138. if (!k)
  139. {
  140. ISC_STATUS err[] = {isc_arg_gds, isc_wish_list};
  141. status->setErrors2(2, err);
  142. return -1;
  143. }
  144. return 1;
  145. }
  146. void getHashData(Firebird::CheckStatusWrapper* status, void* h) override
  147. {
  148. // here key value is returned by hash function as is
  149. // do not do it in production - use some hash function
  150. const ISC_UCHAR& k = holder->getKey();
  151. if (!k)
  152. {
  153. ISC_STATUS err[] = {isc_arg_gds, isc_wish_list};
  154. status->setErrors2(2, err);
  155. return;
  156. }
  157. memcpy(h, &k, 1);
  158. }
  159. private:
  160. CryptKeyHolder* holder;
  161. };
  162. class NamedCallback : public ICryptKeyCallbackImpl<NamedCallback, CheckStatusWrapper>
  163. {
  164. public:
  165. NamedCallback(NamedCallback* n, const char* nm, ISC_UCHAR k)
  166. : next(n), key(k)
  167. {
  168. strncpy(name, nm, sizeof(name));
  169. name[sizeof(name) - 1] = 0;
  170. }
  171. unsigned int callback(unsigned int, const void*, unsigned int length, void* buffer) override
  172. {
  173. memcpy(buffer, &key, 1);
  174. return 1;
  175. }
  176. int getHashLength(Firebird::CheckStatusWrapper* status) override
  177. {
  178. return 1;
  179. }
  180. void getHashData(Firebird::CheckStatusWrapper* status, void* h) override
  181. {
  182. // here key value is returned by hash function as is
  183. // do not do it in production - use some hash function
  184. memcpy(h, &key, 1);
  185. }
  186. ~NamedCallback()
  187. {
  188. delete next;
  189. }
  190. char name[32];
  191. NamedCallback* next;
  192. ISC_UCHAR key;
  193. };
  194. CallbackInterface callbackInterface;
  195. NamedCallback *named;
  196. CheckStatusWrapper tempStatus;
  197. IPluginConfig* config;
  198. ISC_UCHAR key;
  199. bool init;
  200. std::atomic_int refCounter;
  201. IReferenceCounted* owner;
  202. IConfigEntry* getEntry(CheckStatusWrapper* status, const char* entryName);
  203. };
  204. IConfigEntry* CryptKeyHolder::getEntry(CheckStatusWrapper* status, const char* entryName)
  205. {
  206. IConfig* def = config->getDefaultConfig(status);
  207. if (status->getState() & Firebird::IStatus::STATE_ERRORS)
  208. return NULL;
  209. IConfigEntry* confEntry = def->find(status, entryName);
  210. def->release();
  211. if (status->getState() & Firebird::IStatus::STATE_ERRORS)
  212. return NULL;
  213. return confEntry;
  214. }
  215. int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
  216. {
  217. if (key != 0)
  218. return 1;
  219. IConfigEntry* confEntry = getEntry(status, "Auto");
  220. if (confEntry)
  221. {
  222. FB_BOOLEAN b = confEntry->getBoolValue();
  223. confEntry->release();
  224. if (b)
  225. {
  226. confEntry = getEntry(status, "Key");
  227. if (confEntry)
  228. {
  229. key = static_cast<ISC_UCHAR>(confEntry->getIntValue());
  230. confEntry->release();
  231. }
  232. else
  233. key = 0x5a;
  234. return 1;
  235. }
  236. }
  237. if (callback && callback->callback(0, NULL, 1, &key) != 1)
  238. {
  239. key = 0;
  240. return 0;
  241. }
  242. return 1;
  243. }
  244. ICryptKeyCallback* CryptKeyHolder::keyHandle(CheckStatusWrapper* status, const char* keyName)
  245. {
  246. if (keyName[0] == 0)
  247. return &callbackInterface;
  248. for (NamedCallback* n = named; n; n = n->next)
  249. {
  250. if (strcmp(keyName, n->name) == 0)
  251. return n;
  252. }
  253. char kn[40];
  254. strcpy(kn, "Key");
  255. strncat(kn, keyName, sizeof(kn) - 3 - 1);
  256. kn[sizeof(kn) - 1] = 0;
  257. IConfigEntry* confEntry = getEntry(status, kn);
  258. if (confEntry)
  259. {
  260. int k = static_cast<int>(confEntry->getIntValue());
  261. confEntry->release();
  262. if (k > 0 && k < 256)
  263. {
  264. named = new NamedCallback(named, keyName, static_cast<ISC_UCHAR>(k));
  265. return named;
  266. }
  267. }
  268. return NULL;
  269. }
  270. ICryptKeyCallback* CryptKeyHolder::chainHandle(CheckStatusWrapper* status)
  271. {
  272. return &callbackInterface;
  273. }
  274. class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
  275. {
  276. public:
  277. IPluginBase* createPlugin(CheckStatusWrapper* status, IPluginConfig* factoryParameter)
  278. {
  279. CryptKeyHolder* p = new CryptKeyHolder(factoryParameter);
  280. p->addRef();
  281. return p;
  282. }
  283. };
  284. PluginModule module;
  285. Factory factory;
  286. } // anonymous namespace
  287. extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* m)
  288. {
  289. master = m;
  290. IPluginManager* pluginManager = master->getPluginManager();
  291. module.registerMe(pluginManager);
  292. pluginManager->registerPluginFactory(IPluginManager::TYPE_KEY_HOLDER, "fbSampleKeyHolder",
  293. &factory);
  294. }