ldbm_attrcrypt.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2005 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. /* This file handles attribute encryption.
  41. */
  42. #include "back-ldbm.h"
  43. #include "attrcrypt.h"
  44. #include "pk11func.h"
  45. #include "keyhi.h"
  46. #include "nss.h"
  47. /*
  48. * Todo:
  49. * Remember to free the private structures in the attrinfos, so avoid a leak.
  50. */
  51. attrcrypt_cipher_entry attrcrypt_cipher_list[] = { {ATTRCRYPT_CIPHER_AES, "AES", CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, 128/8, 16} ,
  52. {ATTRCRYPT_CIPHER_DES3 , "3DES" , CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, 112/8, 8},
  53. {0} };
  54. #define KEY_ATTRIBUTE_NAME "nsSymmetricKey"
  55. /*
  56. * We maintain one of these structures per cipher that we handle
  57. */
  58. typedef struct _attrcrypt_cipher_state {
  59. char *cipher_display_name;
  60. PRLock *cipher_lock;
  61. PK11SlotInfo *slot;
  62. PK11SymKey *key;
  63. attrcrypt_cipher_entry *ace;
  64. } attrcrypt_cipher_state;
  65. struct _attrcrypt_state_private {
  66. attrcrypt_cipher_state *acs_array[1];
  67. };
  68. static int attrcrypt_wrap_key(attrcrypt_cipher_state *acs, PK11SymKey *symmetric_key, SECKEYPublicKey *public_key, SECItem *wrapped_symmetric_key);
  69. static int attrcrypt_unwrap_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, SECItem *wrapped_symmetric_key, PK11SymKey **unwrapped_symmetric_key);
  70. /*
  71. * Copied from front-end because it's private to plugins
  72. */
  73. static int
  74. local_valuearray_count( Slapi_Value **va)
  75. {
  76. int i=0;
  77. if(va!=NULL)
  78. {
  79. while(NULL != va[i]) i++;
  80. }
  81. return(i);
  82. }
  83. /*
  84. * Helper functions for key management
  85. */
  86. static Slapi_Entry *
  87. getConfigEntry( const char *dn, Slapi_Entry **e2 ) {
  88. Slapi_DN sdn;
  89. slapi_sdn_init_dn_byref( &sdn, dn );
  90. slapi_search_internal_get_entry( &sdn, NULL, e2,
  91. plugin_get_default_component_id());
  92. slapi_sdn_done( &sdn );
  93. return *e2;
  94. }
  95. /**
  96. * Free an entry
  97. */
  98. static void
  99. freeConfigEntry( Slapi_Entry ** e ) {
  100. if ( (e != NULL) && (*e != NULL) ) {
  101. slapi_entry_free( *e );
  102. *e = NULL;
  103. }
  104. }
  105. static int
  106. attrcrypt_get_ssl_cert_name(char **cert_name)
  107. {
  108. char *config_entry_dn = "cn=RSA,cn=encryption,cn=config";
  109. Slapi_Entry *config_entry = NULL;
  110. *cert_name = NULL;
  111. getConfigEntry(config_entry_dn, &config_entry);
  112. if (NULL == config_entry) {
  113. return -1;
  114. }
  115. *cert_name = slapi_entry_attr_get_charptr( config_entry, "nssslpersonalityssl" );
  116. freeConfigEntry(&config_entry);
  117. return 0;
  118. }
  119. /* Retrieve a symmetric key from dse.ldif for a specified cipher */
  120. static int
  121. attrcrypt_keymgmt_get_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, PK11SymKey **key_from_store)
  122. {
  123. int ret = 0;
  124. Slapi_Entry *entry = NULL;
  125. char *dn_template = "cn=%s,cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config";
  126. char *instance_name = li->inst_name;
  127. char *dn_string = NULL;
  128. Slapi_Attr *keyattr = NULL;
  129. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_get_key\n", 0, 0, 0);
  130. dn_string = slapi_ch_smprintf(dn_template, acs->ace->cipher_display_name, instance_name);
  131. /* Fetch the entry */
  132. getConfigEntry(dn_string, &entry);
  133. /* Did we find the entry ? */
  134. if (NULL != entry) {
  135. SECItem key_to_unwrap = {0};
  136. /* If so then look for the attribute that contains the key */
  137. slapi_entry_attr_find(entry, KEY_ATTRIBUTE_NAME, &keyattr);
  138. if (keyattr != NULL) {
  139. Slapi_Value *v = NULL;
  140. slapi_valueset_first_value( &keyattr->a_present_values, &v);
  141. key_to_unwrap.len = slapi_value_get_length(v);
  142. key_to_unwrap.data = (void*)slapi_value_get_string(v);
  143. }
  144. /* Unwrap it */
  145. ret = attrcrypt_unwrap_key(acs, private_key, &key_to_unwrap, key_from_store);
  146. if (entry) {
  147. freeConfigEntry(&entry);
  148. }
  149. } else {
  150. ret = -2; /* Means: we didn't find the entry (which happens if the key has never been generated) */
  151. }
  152. slapi_ch_free_string(&dn_string);
  153. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_get_key\n", 0, 0, 0);
  154. return ret;
  155. }
  156. /* Store a symmetric key for a given cipher in dse.ldif */
  157. static int
  158. attrcrypt_keymgmt_store_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEYPublicKey *public_key, PK11SymKey *key_to_store)
  159. {
  160. int ret = 0;
  161. SECItem wrapped_symmetric_key = {0};
  162. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_store_key\n", 0, 0, 0);
  163. /* Wrap the key and then store it in the right place in dse.ldif */
  164. ret = attrcrypt_wrap_key(acs, key_to_store, public_key, &wrapped_symmetric_key);
  165. if (!ret) {
  166. /* Make the entry to store */
  167. Slapi_Entry *e = NULL;
  168. Slapi_PBlock *pb = slapi_pblock_new();
  169. Slapi_Value *key_value = NULL;
  170. struct berval key_as_berval = {0};
  171. int rc = 0;
  172. char *entry_template =
  173. "dn: cn=%s,cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config\n"
  174. "objectclass:top\n"
  175. "objectclass:extensibleObject\n"
  176. "cn:%s\n";
  177. char *instance_name = li->inst_name;
  178. char *entry_string = slapi_ch_smprintf(entry_template,acs->ace->cipher_display_name,instance_name,acs->ace->cipher_display_name);
  179. e = slapi_str2entry(entry_string, 0);
  180. /* Add the key as a binary attribute */
  181. key_as_berval.bv_val = (char *)wrapped_symmetric_key.data;
  182. key_as_berval.bv_len = wrapped_symmetric_key.len;
  183. key_value = slapi_value_new_berval(&key_as_berval);
  184. /* key_value is now a copy of key_as_berval - free wrapped_symmetric_key */
  185. slapi_ch_free_string((char **)&wrapped_symmetric_key.data);
  186. slapi_entry_add_value(e, KEY_ATTRIBUTE_NAME, key_value);
  187. slapi_value_free(&key_value);
  188. /* Store the entry */
  189. slapi_add_entry_internal_set_pb(pb, e, NULL, li->inst_li->li_identity, 0);
  190. rc = slapi_add_internal_pb(pb);
  191. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  192. if (rc != LDAP_SUCCESS) {
  193. char *resulttext = NULL;
  194. slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &resulttext);
  195. LDAPDebug(LDAP_DEBUG_ANY, "attrcrypt_keymgmt_store_key: failed to add config key entries to the DSE: %d: %s: %s\n", rc, ldap_err2string(rc), resulttext ? resulttext : "unknown");
  196. ret = -1;
  197. }
  198. if (entry_string) {
  199. slapi_ch_free((void**)&entry_string);
  200. }
  201. if (pb) {
  202. slapi_pblock_destroy(pb);
  203. }
  204. }
  205. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_store_key\n", 0, 0, 0);
  206. return ret;
  207. }
  208. /*
  209. * Helper functions for key generation and wrapping
  210. */
  211. /* Wrap a key with the server's public assymetric key for storage */
  212. static int
  213. attrcrypt_wrap_key(attrcrypt_cipher_state *acs, PK11SymKey *symmetric_key, SECKEYPublicKey *public_key, SECItem *wrapped_symmetric_key)
  214. {
  215. int ret = 0;
  216. SECStatus s = 0;
  217. CK_MECHANISM_TYPE wrap_mechanism = CKM_RSA_PKCS;
  218. SECKEYPublicKey *wrapping_key = public_key;
  219. wrapped_symmetric_key->len = slapd_SECKEY_PublicKeyStrength(public_key);
  220. wrapped_symmetric_key->data = (unsigned char *)slapi_ch_malloc(wrapped_symmetric_key->len);
  221. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_wrap_key\n", 0, 0, 0);
  222. s = slapd_pk11_PubWrapSymKey(wrap_mechanism, wrapping_key, symmetric_key, wrapped_symmetric_key);
  223. if (SECSuccess != s) {
  224. ret = -1;
  225. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_wrap_key: failed to wrap key for cipher %s\n", acs->ace->cipher_display_name, 0, 0);
  226. }
  227. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_wrap_key\n", 0, 0, 0);
  228. return ret;
  229. }
  230. /* Unwrap a key previously wrapped with the server's private key */
  231. static int
  232. attrcrypt_unwrap_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, SECItem *wrapped_symmetric_key, PK11SymKey **unwrapped_symmetric_key)
  233. {
  234. int ret = 0;
  235. CK_MECHANISM_TYPE wrap_mechanism = acs->ace->wrap_mechanism;
  236. SECKEYPrivateKey *unwrapping_key = private_key;
  237. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_unwrap_key\n", 0, 0, 0);
  238. *unwrapped_symmetric_key = slapd_pk11_PubUnwrapSymKey(unwrapping_key, wrapped_symmetric_key, wrap_mechanism, CKA_UNWRAP, 0);
  239. if (NULL == *unwrapped_symmetric_key) {
  240. ret = -1;
  241. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_unwrap_key: failed to unwrap key for cipher %s\n", acs->ace->cipher_display_name, 0, 0);
  242. }
  243. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_unwrap_key\n", 0, 0, 0);
  244. return ret;
  245. }
  246. /* Generate a random key for a specified cipher */
  247. static int
  248. attrcrypt_generate_key(attrcrypt_cipher_state *acs,PK11SymKey **symmetric_key)
  249. {
  250. int ret = -1;
  251. PK11SymKey *new_symmetric_key = NULL;
  252. *symmetric_key = NULL;
  253. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_generate_key\n", 0, 0, 0);
  254. new_symmetric_key = slapd_pk11_KeyGen(acs->slot, acs->ace->key_gen_mechanism, NULL, acs->ace->key_size, NULL);
  255. if (new_symmetric_key) {
  256. *symmetric_key = new_symmetric_key;
  257. ret = 0;
  258. }
  259. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_generate_key\n", 0, 0, 0);
  260. return ret;
  261. }
  262. static int
  263. attrcrypt_fetch_public_key(SECKEYPublicKey **public_key)
  264. {
  265. int ret = 0;
  266. CERTCertificate *cert = NULL;
  267. SECKEYPublicKey *key = NULL;
  268. PRErrorCode errorCode = 0;
  269. char *default_cert_name = "server-cert";
  270. char *cert_name = NULL;
  271. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_fetch_public_key\n", 0, 0, 0);
  272. *public_key = NULL;
  273. /* Try to grok the server cert name from the SSL config */
  274. ret = attrcrypt_get_ssl_cert_name(&cert_name);
  275. if (ret) {
  276. cert_name = default_cert_name;
  277. }
  278. /* We assume that the server core pin stuff is already enabled, via the SSL initialization done in the front-end */
  279. cert = slapd_pk11_findCertFromNickname(cert_name, NULL);
  280. if (cert == NULL) {
  281. errorCode = PR_GetError();
  282. LDAPDebug(LDAP_DEBUG_ANY,"Can't find certificate %s in attrcrypt_fetch_public_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
  283. }
  284. if( cert != NULL ) {
  285. key = slapd_CERT_ExtractPublicKey(cert);
  286. }
  287. if (key == NULL) {
  288. errorCode = PR_GetError();
  289. LDAPDebug(LDAP_DEBUG_ANY,"Can't get private key from cert %s in attrcrypt_fetch_public_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
  290. ret = -1;
  291. }
  292. if (cert) {
  293. slapd_pk11_CERT_DestroyCertificate(cert);
  294. }
  295. if (key) {
  296. *public_key = key;
  297. }else {
  298. ret = -1;
  299. }
  300. if (cert_name != default_cert_name) {
  301. slapi_ch_free_string(&cert_name);
  302. }
  303. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_fetch_public_key\n", 0, 0, 0);
  304. return ret;
  305. }
  306. static int
  307. attrcrypt_fetch_private_key(SECKEYPrivateKey **private_key)
  308. {
  309. int ret = 0;
  310. CERTCertificate *cert = NULL;
  311. SECKEYPrivateKey *key = NULL;
  312. PRErrorCode errorCode = 0;
  313. char *default_cert_name = "server-cert";
  314. char *cert_name = NULL;
  315. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_fetch_private_key\n", 0, 0, 0);
  316. *private_key = NULL;
  317. /* Try to grok the server cert name from the SSL config */
  318. ret = attrcrypt_get_ssl_cert_name(&cert_name);
  319. if (ret) {
  320. cert_name = default_cert_name;
  321. }
  322. /* We assume that the server core pin stuff is already enabled, via the SSL initialization done in the front-end */
  323. cert = slapd_pk11_findCertFromNickname(cert_name, NULL);
  324. if (cert == NULL) {
  325. errorCode = PR_GetError();
  326. LDAPDebug(LDAP_DEBUG_ANY,"Can't find certificate %s in attrcrypt_fetch_private_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
  327. }
  328. if( cert != NULL ) {
  329. key = slapd_pk11_findKeyByAnyCert(cert, NULL);
  330. }
  331. if (key == NULL) {
  332. errorCode = PR_GetError();
  333. LDAPDebug(LDAP_DEBUG_ANY,"Can't get private key from cert %s in attrcrypt_fetch_private_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
  334. ret = -1;
  335. }
  336. if (cert) {
  337. slapd_pk11_CERT_DestroyCertificate(cert);
  338. }
  339. if (key) {
  340. *private_key = key;
  341. } else {
  342. ret = -1;
  343. }
  344. if (cert_name != default_cert_name) {
  345. slapi_ch_free_string(&cert_name);
  346. }
  347. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_fetch_private_key\n", 0, 0, 0);
  348. return ret;
  349. }
  350. /*
  351. CKM_AES_CBC_PAD
  352. CKM_DES3_CBC_PAD
  353. */
  354. /* Initialize the structure for a single cipher */
  355. static int
  356. attrcrypt_cipher_init(ldbm_instance *li, attrcrypt_cipher_entry *ace, SECKEYPrivateKey *private_key, SECKEYPublicKey *public_key, attrcrypt_cipher_state *acs)
  357. {
  358. int ret = 0;
  359. PK11SymKey *symmetric_key = NULL;
  360. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_cipher_init\n", 0, 0, 0);
  361. acs->cipher_lock = PR_NewLock();
  362. /* Fill in some basic stuff */
  363. acs->ace = ace;
  364. acs->cipher_display_name = ace->cipher_display_name;
  365. if (NULL == acs->cipher_lock) {
  366. LDAPDebug(LDAP_DEBUG_ANY,"Failed to create cipher lock in attrcrypt_cipher_init\n", 0, 0, 0);
  367. }
  368. acs->slot = slapd_pk11_GetInternalKeySlot();
  369. if (NULL == acs->slot) {
  370. LDAPDebug(LDAP_DEBUG_ANY,"Failed to create a slot for cipher %s in attrcrypt_cipher_entry\n", acs->cipher_display_name, 0, 0);
  371. goto error;
  372. }
  373. /* Try to get the symmetric key for this cipher */
  374. ret = attrcrypt_keymgmt_get_key(li,acs,private_key,&symmetric_key);
  375. if (ret) {
  376. if (-2 == ret) {
  377. LDAPDebug(LDAP_DEBUG_ANY,"No symmetric key found for cipher %s in backend %s, attempting to create one...\n", acs->cipher_display_name, li->inst_name, 0);
  378. ret = attrcrypt_generate_key(acs,&symmetric_key);
  379. if (ret) {
  380. LDAPDebug(LDAP_DEBUG_ANY,"Failed to generate key for %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
  381. }
  382. if (symmetric_key) {
  383. ret = attrcrypt_keymgmt_store_key(li,acs,public_key,symmetric_key);
  384. if (ret) {
  385. LDAPDebug(LDAP_DEBUG_ANY,"Failed to store key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
  386. } else {
  387. LDAPDebug(LDAP_DEBUG_ANY,"Key for cipher %s successfully generated and stored\n", acs->cipher_display_name, 0, 0);
  388. }
  389. }
  390. } else {
  391. LDAPDebug(LDAP_DEBUG_ANY,"Failed to retrieve key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
  392. }
  393. }
  394. if (symmetric_key) {
  395. /* we loaded the symmetric key, store it in the acs */
  396. acs->key = symmetric_key;
  397. }
  398. error:
  399. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_cipher_init\n", 0, 0, 0);
  400. return ret;
  401. }
  402. static void
  403. attrcrypt_acs_list_add(ldbm_instance *li,attrcrypt_cipher_state *acs)
  404. {
  405. /* Realloc the existing list and add to the end */
  406. attrcrypt_cipher_state **current = NULL;
  407. size_t list_size = 0;
  408. /* Is the list already there ? */
  409. if (NULL == li->inst_attrcrypt_state_private) {
  410. /* If not, add it */
  411. li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_calloc(sizeof(attrcrypt_cipher_state *), 2); /* 2 == The pointer and a NULL terminator */
  412. } else {
  413. /* Otherwise re-size it */
  414. for (current = &(li->inst_attrcrypt_state_private->acs_array[0]); *current; current++) {
  415. list_size++;
  416. }
  417. li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_realloc((char*)li->inst_attrcrypt_state_private,sizeof(attrcrypt_cipher_state *) * (list_size + 2));
  418. li->inst_attrcrypt_state_private->acs_array[list_size + 1] = NULL;
  419. }
  420. li->inst_attrcrypt_state_private->acs_array[list_size] = acs;
  421. }
  422. int
  423. attrcrypt_init(ldbm_instance *li)
  424. {
  425. int ret = 0;
  426. attrcrypt_cipher_entry *ace = NULL;
  427. SECKEYPrivateKey *private_key = NULL;
  428. SECKEYPublicKey *public_key = NULL;
  429. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_init\n", 0, 0, 0);
  430. if (slapd_security_library_is_initialized()) {
  431. li->inst_attrcrypt_state_private = NULL;
  432. /* Get the server's private key, which is used to unwrap the stored symmetric keys */
  433. ret = attrcrypt_fetch_private_key(&private_key);
  434. if (!ret) {
  435. ret = attrcrypt_fetch_public_key(&public_key);
  436. if (!ret) {
  437. for (ace = attrcrypt_cipher_list; ace && ace->cipher_number && !ret; ace++) {
  438. /* Make a state object for this cipher */
  439. attrcrypt_cipher_state *acs = (attrcrypt_cipher_state *) slapi_ch_calloc(sizeof(attrcrypt_cipher_state),1);
  440. ret = attrcrypt_cipher_init(li, ace, private_key, public_key, acs);
  441. if (ret) {
  442. LDAPDebug(LDAP_DEBUG_ANY,"Failed to initialize cipher %s in attrcrypt_init\n", ace->cipher_display_name, 0, 0);
  443. slapi_ch_free((void **)&acs);
  444. } else {
  445. /* Since we succeeded, add the acs to the backend instance list */
  446. attrcrypt_acs_list_add(li,acs);
  447. LDAPDebug(LDAP_DEBUG_TRACE,"Initialized cipher %s in attrcrypt_init\n", ace->cipher_display_name, 0, 0);
  448. }
  449. }
  450. }
  451. slapd_pk11_DestroyPublicKey(public_key);
  452. public_key = NULL;
  453. }
  454. slapd_pk11_DestroyPrivateKey(private_key);
  455. private_key = NULL;
  456. } else {
  457. if (li->attrcrypt_configured) {
  458. LDAPDebug(LDAP_DEBUG_ANY,"Warning: encryption is configured in backend %s, but because SSL is not enabled, database encryption is not available and the configuration will be overridden.\n", li->inst_name, 0, 0);
  459. }
  460. }
  461. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_init : %d\n", ret, 0, 0);
  462. return ret;
  463. }
  464. /*
  465. * Called by the config code when a new attribute is added,
  466. * to make sure that we already have the runtime state and key
  467. * stored for that cipher. If not, we attmept to make it.
  468. * If this function succeeds, then its ok to go on to use the
  469. * cipher.
  470. */
  471. int attrcrypt_check_enable_cipher(attrcrypt_cipher_entry *ace)
  472. {
  473. int ret = 0;
  474. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_check_enable_cipher\n", 0, 0, 0);
  475. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_check_enable_cipher\n", 0, 0, 0);
  476. return ret;
  477. }
  478. int
  479. attrcrypt_cleanup(attrcrypt_cipher_state *acs)
  480. {
  481. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_cleanup\n", 0, 0, 0);
  482. if (acs->key) {
  483. slapd_pk11_FreeSymKey(acs->key);
  484. }
  485. if (acs->slot) {
  486. slapd_pk11_FreeSlot(acs->slot);
  487. }
  488. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_cleanup\n", 0, 0, 0);
  489. return 0;
  490. }
  491. static attrcrypt_cipher_state *
  492. attrcrypt_get_acs(backend *be, attrcrypt_private *priv)
  493. {
  494. /* Walk the list of acs objects looking for the one for our cipher */
  495. int cipher = priv->attrcrypt_cipher;
  496. ldbm_instance *li = (ldbm_instance *) be->be_instance_info;
  497. attrcrypt_state_private* iasp = li->inst_attrcrypt_state_private;
  498. if (iasp) {
  499. attrcrypt_cipher_state **current = &(iasp->acs_array[0]);
  500. while (current) {
  501. if ((*current)->ace->cipher_number == cipher) {
  502. return *current;
  503. }
  504. current++;
  505. }
  506. }
  507. return NULL;
  508. }
  509. #if defined(DEBUG_ATTRCRYPT)
  510. static void log_bytes(char* format_string, unsigned char *bytes, size_t length)
  511. {
  512. size_t max_length = 40;
  513. size_t truncated_length = (length > max_length) ? max_length : length;
  514. size_t x = 0;
  515. char *print_buffer = NULL;
  516. char *print_ptr = NULL;
  517. print_buffer = (char*)slapi_ch_malloc((truncated_length * 3) + 1);
  518. print_ptr = print_buffer;
  519. for (x = 0; x < truncated_length; x++) {
  520. print_ptr += sprintf(print_ptr, "%02x ", bytes[x]);
  521. }
  522. LDAPDebug(LDAP_DEBUG_ANY,format_string, print_buffer, length, 0);
  523. slapi_ch_free((void**)&print_buffer);
  524. }
  525. #endif
  526. /* Either encipher or decipher an attribute value */
  527. static int
  528. attrcrypt_crypto_op(attrcrypt_private *priv, backend *be, struct attrinfo *ai, char *in_data, size_t in_size, char **out_data, size_t *out_size, int encrypt)
  529. {
  530. int ret = -1;
  531. SECStatus secret = 0;
  532. PK11Context* sec_context = NULL;
  533. SECItem iv_item = {0};
  534. SECItem *security_parameter = NULL;
  535. int output_buffer_length = 0;
  536. int output_buffer_size1 = 0;
  537. unsigned int output_buffer_size2 = 0;
  538. unsigned char *output_buffer = NULL;
  539. attrcrypt_cipher_state *acs = NULL;
  540. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op\n", 0, 0, 0);
  541. acs = attrcrypt_get_acs(be,ai->ai_attrcrypt);
  542. if (NULL == acs) {
  543. /* This happens if SSL/NSS has not been enabled */
  544. return -1;
  545. }
  546. #if defined(DEBUG_ATTRCRYPT)
  547. if (encrypt) {
  548. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op encrypt '%s' (%d)\n", in_data, in_size, 0);
  549. } else {
  550. log_bytes("attrcrypt_crypto_op decrypt '%s' (%d)\n", (unsigned char *)in_data, in_size);
  551. }
  552. #endif
  553. /* Allocate the output buffer */
  554. output_buffer_length = in_size + 16;
  555. output_buffer = (unsigned char *)slapi_ch_malloc(output_buffer_length);
  556. /* Now call NSS to do the cipher op */
  557. iv_item.data = (unsigned char *)"aaaaaaaaaaaaaaaa"; /* ptr to an array of IV bytes */
  558. iv_item.len = acs->ace->iv_length; /* length of the array of IV bytes */
  559. security_parameter = slapd_pk11_ParamFromIV(acs->ace->cipher_mechanism, &iv_item);
  560. if (NULL == security_parameter) {
  561. int errorCode = PR_GetError();
  562. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed to make IV for cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
  563. goto error;
  564. }
  565. sec_context = slapd_pk11_createContextBySymKey(acs->ace->cipher_mechanism, (encrypt ? CKA_ENCRYPT : CKA_DECRYPT), acs->key, security_parameter);
  566. if (NULL == sec_context) {
  567. int errorCode = PR_GetError();
  568. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
  569. goto error;
  570. }
  571. secret = slapd_pk11_cipherOp(sec_context, output_buffer, &output_buffer_size1, output_buffer_length, (unsigned char *)in_data, in_size);
  572. if (SECSuccess != secret) {
  573. int errorCode = PR_GetError();
  574. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
  575. goto error;
  576. }
  577. #if defined(DEBUG_ATTRCRYPT)
  578. LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_cipherOp %d\n", output_buffer_size1, 0, 0);
  579. #endif
  580. secret = slapd_pk11_DigestFinal(sec_context, output_buffer + output_buffer_size1, &output_buffer_size2, output_buffer_length - output_buffer_size1);
  581. if (SECSuccess != secret) {
  582. int errorCode = PR_GetError();
  583. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op digest final failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
  584. goto error;
  585. } else {
  586. #if defined(DEBUG_ATTRCRYPT)
  587. int recurse = 1;
  588. if (encrypt) {
  589. log_bytes("slapd_pk11_DigestFinal '%s' (%d)\n", output_buffer, output_buffer_size1 + output_buffer_size2);
  590. } else {
  591. LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_DigestFinal '%s', %u\n", output_buffer, output_buffer_size2, 0);
  592. }
  593. if (*out_size == -1) {
  594. recurse = 0;
  595. }
  596. #endif
  597. *out_size = output_buffer_size1 + output_buffer_size2;
  598. *out_data = (char *)output_buffer;
  599. ret = 0; /* success */
  600. #if defined(DEBUG_ATTRCRYPT)
  601. if (recurse) {
  602. char *redo_data = NULL;
  603. size_t redo_size = -1;
  604. int redo_ret;
  605. LDAPDebug(LDAP_DEBUG_ANY,"------> check result of crypto op\n", 0, 0, 0);
  606. redo_ret = attrcrypt_crypto_op(priv, be, ai, *out_data, *out_size, &redo_data, &redo_size, !encrypt);
  607. slapi_log_error(SLAPI_LOG_FATAL, "DEBUG_ATTRCRYPT",
  608. "orig length %ld redone length %ld\n", in_size, redo_size);
  609. log_bytes("DEBUG_ATTRCRYPT orig bytes '%s' (%d)\n", (unsigned char *)in_data, in_size);
  610. log_bytes("DEBUG_ATTRCRYPT redo bytes '%s' (%d)\n", (unsigned char *)redo_data, redo_size);
  611. LDAPDebug(LDAP_DEBUG_ANY,"<------ check result of crypto op\n", 0, 0, 0);
  612. }
  613. #endif
  614. }
  615. error:
  616. if (sec_context) {
  617. slapd_pk11_DestroyContext(sec_context, PR_TRUE);
  618. }
  619. if (security_parameter) {
  620. slapd_SECITEM_FreeItem(security_parameter, PR_TRUE);
  621. }
  622. if (ret) {
  623. slapi_ch_free_string((char **)&output_buffer);
  624. }
  625. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op\n", 0, 0, 0);
  626. return ret;
  627. }
  628. static int
  629. attrcrypt_crypto_op_value(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value *invalue, Slapi_Value **outvalue, int encrypt)
  630. {
  631. int ret = 0;
  632. char *in_data = NULL;
  633. size_t in_size = 0;
  634. char *out_data = NULL;
  635. size_t out_size = 0;
  636. struct berval *bval = NULL;
  637. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_value\n", 0, 0, 0);
  638. bval = (struct berval *) slapi_value_get_berval(invalue);
  639. in_data = bval->bv_val;
  640. in_size = bval->bv_len;
  641. ret = attrcrypt_crypto_op(priv,be,ai,in_data,in_size,&out_data,&out_size,encrypt);
  642. if (0 == ret) {
  643. struct berval outbervalue = {0};
  644. outbervalue.bv_len = out_size;
  645. outbervalue.bv_val = out_data;
  646. /* This call makes a copy of the payload data, so we need to free the original data after making the call */
  647. *outvalue = slapi_value_new_berval(&outbervalue);
  648. slapi_ch_free((void**)&out_data);
  649. }
  650. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_value: %d\n", ret, 0, 0);
  651. return ret;
  652. }
  653. int
  654. attrcrypt_crypto_op_value_replace(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value *inoutvalue, int encrypt)
  655. {
  656. int ret = 0;
  657. char *in_data = NULL;
  658. size_t in_size = 0;
  659. char *out_data = NULL;
  660. size_t out_size = 0;
  661. struct berval *bval = NULL;
  662. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_value_replace\n", 0, 0, 0);
  663. bval = (struct berval *) slapi_value_get_berval(inoutvalue);
  664. in_data = bval->bv_val;
  665. in_size = bval->bv_len;
  666. ret = attrcrypt_crypto_op(priv,be,ai,in_data,in_size,&out_data,&out_size,encrypt);
  667. if (0 == ret) {
  668. struct berval outbervalue = {0};
  669. outbervalue.bv_len = out_size;
  670. outbervalue.bv_val = out_data;
  671. /* This takes a copy of the payload, so we need to free it now */
  672. slapi_value_set_berval(inoutvalue,&outbervalue);
  673. slapi_ch_free((void**)&out_data);
  674. }
  675. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_value_replace: %d\n", ret, 0, 0);
  676. return ret;
  677. }
  678. static int
  679. attrcrypt_crypto_op_values(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value **invalues, Slapi_Value ***outvalues, int encrypt)
  680. {
  681. int ret = 0;
  682. int i = 0;
  683. Slapi_Value **encrypted_values = NULL;
  684. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_values\n", 0, 0, 0);
  685. encrypted_values = (Slapi_Value **) slapi_ch_calloc(sizeof(Slapi_Value *),local_valuearray_count(invalues) + 1);
  686. for ( i = 0; (invalues[i] != NULL) && (ret == 0); i++ ) {
  687. Slapi_Value *encrypted_value = NULL;
  688. ret = attrcrypt_crypto_op_value(priv,be,ai,invalues[i],&encrypted_value,encrypt);
  689. if (0 == ret) {
  690. encrypted_values[i] = encrypted_value;
  691. }
  692. }
  693. *outvalues = encrypted_values;
  694. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_values: %d\n", ret, 0, 0);
  695. return ret;
  696. }
  697. static int
  698. attrcrypt_crypto_op_values_replace(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value **invalues, int encrypt)
  699. {
  700. int ret = 0;
  701. int i = 0;
  702. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_values_replace\n", 0, 0, 0);
  703. for ( i = 0; (invalues[i] != NULL) && (ret == 0); i++ ) {
  704. ret = attrcrypt_crypto_op_value_replace(priv,be,ai,invalues[i],encrypt);
  705. if (ret) {
  706. break;
  707. }
  708. }
  709. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_values_replace\n", 0, 0, 0);
  710. return ret;
  711. }
  712. /* Modifies the entry in-place to decrypt any encrypted attributes */
  713. int
  714. attrcrypt_decrypt_entry(backend *be, struct backentry *e)
  715. {
  716. int ret = 0;
  717. int rc = 0;
  718. Slapi_Attr *attr = NULL;
  719. char *type = NULL;
  720. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_decrypt_entry\n", 0, 0, 0);
  721. /* Scan through the entry's attributes, looking to see if any are configured for crypto */
  722. for ( rc = slapi_entry_first_attr( e->ep_entry, &attr ); rc == 0 && attr ; rc = slapi_entry_next_attr( e->ep_entry, attr, &attr )) {
  723. struct attrinfo *ai = NULL;
  724. Slapi_Value *value = NULL;
  725. int i = 0;
  726. slapi_attr_get_type( attr, &type );
  727. ainfo_get(be, type, &ai);
  728. if (ai && ai->ai_attrcrypt) {
  729. i = slapi_attr_first_value(attr,&value);
  730. while (NULL != value && i != -1)
  731. {
  732. /* Now decrypt the attribute values in place on the original entry */
  733. ret = attrcrypt_crypto_op_value_replace(ai->ai_attrcrypt,be,ai,value,0);
  734. if (ret) {
  735. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_decrypt_entry: FAILING because decryption operation failed\n", 0, 0, 0);
  736. return ret;
  737. }
  738. i = slapi_attr_next_value(attr,i,&value);
  739. }
  740. /* Now do the same thing with deleted values */
  741. i = attr_first_deleted_value(attr,&value);
  742. while (NULL != value && i != -1)
  743. {
  744. /* Now decrypt the attribute values in place on the original entry */
  745. ret = attrcrypt_crypto_op_value_replace(ai->ai_attrcrypt,be,ai,value,0);
  746. if (ret) {
  747. LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_decrypt_entry: FAILING because decryption operation failed\n", 0, 0, 0);
  748. return ret;
  749. }
  750. i = attr_next_deleted_value(attr,i,&value);
  751. }
  752. }
  753. }
  754. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_decrypt_entry\n", 0, 0, 0);
  755. return ret;
  756. }
  757. /* Encrypts attributes on this entry in-place (only changes the attribute data, nothing else)
  758. */
  759. int
  760. attrcrypt_encrypt_entry_inplace(backend *be, const struct backentry *inout)
  761. {
  762. int ret = 0;
  763. int rc = 0;
  764. char *type = NULL;
  765. Slapi_Attr *attr = NULL;
  766. Slapi_Value **svals = NULL;
  767. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_entry_inplace\n", 0, 0, 0);
  768. /* Scan the entry's attributes looking for any that are configured for encryption */
  769. for ( rc = slapi_entry_first_attr( inout->ep_entry, &attr ); rc == 0;
  770. rc = slapi_entry_next_attr( inout->ep_entry, attr, &attr ) ) {
  771. struct attrinfo *ai = NULL;
  772. slapi_attr_get_type( attr, &type );
  773. ainfo_get(be, type, &ai);
  774. if (ai && ai->ai_attrcrypt) {
  775. svals = attr_get_present_values(attr);
  776. if (svals) {
  777. /* Now encrypt the attribute values in place on the new entry */
  778. ret = attrcrypt_crypto_op_values_replace(ai->ai_attrcrypt,be,ai,svals,1);
  779. }
  780. }
  781. }
  782. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_entry_inplace\n", 0, 0, 0);
  783. return ret;
  784. }
  785. /* Makes a copy of the entry that has all necessary attributes encrypted
  786. * as a performance optimization, if there are no attributes configured
  787. * for encryption in the entry, then no copy is returned.
  788. */
  789. int
  790. attrcrypt_encrypt_entry(backend *be, const struct backentry *in, struct backentry **out)
  791. {
  792. int ret = 0;
  793. int rc = 0;
  794. struct backentry *new_entry = NULL;
  795. char *type = NULL;
  796. Slapi_Attr *attr = NULL;
  797. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_entry\n", 0, 0, 0);
  798. *out = NULL;
  799. /* Scan the entry's attributes looking for any that are configured for encryption */
  800. for ( rc = slapi_entry_first_attr( in->ep_entry, &attr ); rc == 0;
  801. rc = slapi_entry_next_attr( in->ep_entry, attr, &attr ) ) {
  802. struct attrinfo *ai = NULL;
  803. slapi_attr_get_type( attr, &type );
  804. ainfo_get(be, type, &ai);
  805. if (ai && ai->ai_attrcrypt) {
  806. Slapi_Value **svals = attr_get_present_values(attr);
  807. if (svals) {
  808. Slapi_Value **new_vals = NULL;
  809. /* If we find one, did we make the new entry yet ? */
  810. if (NULL == new_entry) {
  811. /* If not then make it now as a copy of the old entry */
  812. new_entry = backentry_dup((struct backentry *)in);
  813. }
  814. /* Now encrypt the attribute values in place on the new entry */
  815. ret = attrcrypt_crypto_op_values(ai->ai_attrcrypt,be,ai,svals,&new_vals,1);
  816. if (ret) {
  817. LDAPDebug(LDAP_DEBUG_ANY,"Error: attrcrypt_crypto_op_values failed in attrcrypt_encrypt_entry\n", 0, 0, 0);
  818. break;
  819. }
  820. /* DBDB does this call free the old value memory ? */
  821. /* yes, DBDB, but it does not free new_vals - new_vals is copied */
  822. slapi_entry_attr_replace_sv(new_entry->ep_entry, type, new_vals);
  823. valuearray_free(&new_vals);
  824. }
  825. }
  826. }
  827. *out = new_entry;
  828. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_entry\n", 0, 0, 0);
  829. return ret;
  830. }
  831. /*
  832. * Encrypt an index key. There is never any need to decrypt index keys since
  833. * we only ever look them up using plain text.
  834. */
  835. int
  836. attrcrypt_encrypt_index_key(backend *be, struct attrinfo *ai, const struct berval *in, struct berval **out)
  837. {
  838. int ret = 0;
  839. char *in_data = in->bv_val;
  840. size_t in_size = in->bv_len;
  841. char *out_data = NULL;
  842. size_t out_size = 0;
  843. struct berval *out_berval = NULL;
  844. if (ai->ai_attrcrypt) {
  845. LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_index_key\n", 0, 0, 0);
  846. ret = attrcrypt_crypto_op(ai->ai_attrcrypt,be,ai, in_data,in_size,&out_data,&out_size, 1);
  847. if (0 == ret) {
  848. out_berval = (struct berval *)ber_alloc();
  849. if (NULL == out_berval) {
  850. return ENOMEM;
  851. }
  852. out_berval->bv_len = out_size;
  853. /* Because we're making a new berval, we copy the payload pointer in */
  854. /* It's now the responsibility of our caller to free that data */
  855. out_berval->bv_val = out_data;
  856. *out = out_berval;
  857. }
  858. LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_index_key\n", 0, 0, 0);
  859. }
  860. return ret;
  861. }