p≡p engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2205 lines
74 KiB

2 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
4 years ago
4 years ago
8 years ago
7 years ago
6 years ago
6 years ago
8 years ago
4 years ago
4 years ago
4 years ago
4 years ago
2 years ago
4 years ago
2 years ago
2 years ago
2 years ago
4 years ago
4 years ago
8 years ago
2 years ago
2 years ago
8 years ago
8 years ago
7 years ago
3 years ago
3 years ago
8 years ago
8 years ago
4 years ago
3 years ago
8 years ago
8 years ago
4 years ago
7 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
3 years ago
ENGINE-866 feature branch merge (squashed commit) of functionality to set the sticky bit for manually imported keys, to query for that bit in the trust database, and prevention of automatic reset of sticky keys by key reset when devices leave a device group. Squashed commit of the following: commit c64d850dc4bfe5a9dfd54aa94eea08a75ff69191 Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:29:32 2021 +0100 ENGINE-866: doc'd bit getter function commit ad725b5b7c742300a6a182ad8b058db23dbc3cfb Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:23:49 2021 +0100 ENGINE-866: Key reset tested on mixed sticky and not sticky keys and does what it should. commit 0ffbdde7b598c7c3fff5d797e732dec07685f9be Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:13:53 2021 +0100 ENGINE-866: Add boolean for whether to set the sticky bit or not with set_own_imported_key. the adapter should filter this out for apps, I guess, according to Volker commit 23fec59a9a4ede0682a9ebcb9a61e78456e7d8d4 Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 14:53:19 2021 +0100 ENGINE-866: Test and use the sticky bit commit 562239fda874623c40893c382a8f82df9e002ef5 Author: Krista Bennett <krista@pep.foundation> Date: Thu Feb 25 16:47:47 2021 +0100 ENGINE-866: moved bit from key to trust, created set_own_imported_key to replace set_own_key FOR MAIL APPS (does NOT replace it for key reset, as the new function can generate a passphrase error, whereas set_own_key cannot), and did an initial test to ensure the setter/getter functions work on the DB. commit 594133cfdee966adbaa66c62133ede1ca917bca0 Author: Krista Bennett <krista@pep.foundation> Date: Wed Feb 24 11:16:21 2021 +0100 Commented out the or'd identity.flags / pgp_keypair.flags in the sql code for the get_identity functions; we've never HAD a pgp_keypair flag before, so it never hurt before, but at this point, we're going to introduce them, and I don't want trouble. If fdik wants them or'd, fine, we'll have to change the values in the keyflags to be disjoint from the identity flags so they can coexist, but for now, they are out. commit 99831445b3e22e1386aa0f86414fdb6939e5ebaf Merge: 8ba53ece d1664cf5 Author: Krista Bennett <krista@pep.foundation> Date: Wed Feb 24 10:15:53 2021 +0100 Merge branch 'master' into ENGINE-866 commit 8ba53ece06773168a9188373d1be5f13d99b2f6e Merge: 168e2cf9 c52f4d39 Author: Krista Bennett <krista@pep.foundation> Date: Mon Feb 22 20:06:08 2021 +0100 Merged in engine_sql changes commit 168e2cf9578b12157b98da8b26e598f0a1448d9e Author: Krista Bennett <krista@pep.foundation> Date: Mon Feb 22 19:03:35 2021 +0100 ENGINE-866: Added sticky bit in database for manually set keys
1 year ago
3 years ago
3 years ago
ENGINE-866 feature branch merge (squashed commit) of functionality to set the sticky bit for manually imported keys, to query for that bit in the trust database, and prevention of automatic reset of sticky keys by key reset when devices leave a device group. Squashed commit of the following: commit c64d850dc4bfe5a9dfd54aa94eea08a75ff69191 Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:29:32 2021 +0100 ENGINE-866: doc'd bit getter function commit ad725b5b7c742300a6a182ad8b058db23dbc3cfb Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:23:49 2021 +0100 ENGINE-866: Key reset tested on mixed sticky and not sticky keys and does what it should. commit 0ffbdde7b598c7c3fff5d797e732dec07685f9be Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:13:53 2021 +0100 ENGINE-866: Add boolean for whether to set the sticky bit or not with set_own_imported_key. the adapter should filter this out for apps, I guess, according to Volker commit 23fec59a9a4ede0682a9ebcb9a61e78456e7d8d4 Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 14:53:19 2021 +0100 ENGINE-866: Test and use the sticky bit commit 562239fda874623c40893c382a8f82df9e002ef5 Author: Krista Bennett <krista@pep.foundation> Date: Thu Feb 25 16:47:47 2021 +0100 ENGINE-866: moved bit from key to trust, created set_own_imported_key to replace set_own_key FOR MAIL APPS (does NOT replace it for key reset, as the new function can generate a passphrase error, whereas set_own_key cannot), and did an initial test to ensure the setter/getter functions work on the DB. commit 594133cfdee966adbaa66c62133ede1ca917bca0 Author: Krista Bennett <krista@pep.foundation> Date: Wed Feb 24 11:16:21 2021 +0100 Commented out the or'd identity.flags / pgp_keypair.flags in the sql code for the get_identity functions; we've never HAD a pgp_keypair flag before, so it never hurt before, but at this point, we're going to introduce them, and I don't want trouble. If fdik wants them or'd, fine, we'll have to change the values in the keyflags to be disjoint from the identity flags so they can coexist, but for now, they are out. commit 99831445b3e22e1386aa0f86414fdb6939e5ebaf Merge: 8ba53ece d1664cf5 Author: Krista Bennett <krista@pep.foundation> Date: Wed Feb 24 10:15:53 2021 +0100 Merge branch 'master' into ENGINE-866 commit 8ba53ece06773168a9188373d1be5f13d99b2f6e Merge: 168e2cf9 c52f4d39 Author: Krista Bennett <krista@pep.foundation> Date: Mon Feb 22 20:06:08 2021 +0100 Merged in engine_sql changes commit 168e2cf9578b12157b98da8b26e598f0a1448d9e Author: Krista Bennett <krista@pep.foundation> Date: Mon Feb 22 19:03:35 2021 +0100 ENGINE-866: Added sticky bit in database for manually set keys
1 year ago
ENGINE-866 feature branch merge (squashed commit) of functionality to set the sticky bit for manually imported keys, to query for that bit in the trust database, and prevention of automatic reset of sticky keys by key reset when devices leave a device group. Squashed commit of the following: commit c64d850dc4bfe5a9dfd54aa94eea08a75ff69191 Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:29:32 2021 +0100 ENGINE-866: doc'd bit getter function commit ad725b5b7c742300a6a182ad8b058db23dbc3cfb Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:23:49 2021 +0100 ENGINE-866: Key reset tested on mixed sticky and not sticky keys and does what it should. commit 0ffbdde7b598c7c3fff5d797e732dec07685f9be Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 15:13:53 2021 +0100 ENGINE-866: Add boolean for whether to set the sticky bit or not with set_own_imported_key. the adapter should filter this out for apps, I guess, according to Volker commit 23fec59a9a4ede0682a9ebcb9a61e78456e7d8d4 Author: Krista Bennett <krista@pep.foundation> Date: Fri Feb 26 14:53:19 2021 +0100 ENGINE-866: Test and use the sticky bit commit 562239fda874623c40893c382a8f82df9e002ef5 Author: Krista Bennett <krista@pep.foundation> Date: Thu Feb 25 16:47:47 2021 +0100 ENGINE-866: moved bit from key to trust, created set_own_imported_key to replace set_own_key FOR MAIL APPS (does NOT replace it for key reset, as the new function can generate a passphrase error, whereas set_own_key cannot), and did an initial test to ensure the setter/getter functions work on the DB. commit 594133cfdee966adbaa66c62133ede1ca917bca0 Author: Krista Bennett <krista@pep.foundation> Date: Wed Feb 24 11:16:21 2021 +0100 Commented out the or'd identity.flags / pgp_keypair.flags in the sql code for the get_identity functions; we've never HAD a pgp_keypair flag before, so it never hurt before, but at this point, we're going to introduce them, and I don't want trouble. If fdik wants them or'd, fine, we'll have to change the values in the keyflags to be disjoint from the identity flags so they can coexist, but for now, they are out. commit 99831445b3e22e1386aa0f86414fdb6939e5ebaf Merge: 8ba53ece d1664cf5 Author: Krista Bennett <krista@pep.foundation> Date: Wed Feb 24 10:15:53 2021 +0100 Merge branch 'master' into ENGINE-866 commit 8ba53ece06773168a9188373d1be5f13d99b2f6e Merge: 168e2cf9 c52f4d39 Author: Krista Bennett <krista@pep.foundation> Date: Mon Feb 22 20:06:08 2021 +0100 Merged in engine_sql changes commit 168e2cf9578b12157b98da8b26e598f0a1448d9e Author: Krista Bennett <krista@pep.foundation> Date: Mon Feb 22 19:03:35 2021 +0100 ENGINE-866: Added sticky bit in database for manually set keys
1 year ago
2 years ago
  1. /**
  2. * @file keymanagement.c
  3. * @brief Implementation of functions to manage keys
  4. * (and identities when in relation to keys)
  5. * @license GNU General Public License 3.0 - see LICENSE.txt
  6. */
  7. #include "platform.h"
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <assert.h>
  12. #include <ctype.h>
  13. #include "pEp_internal.h"
  14. #include "keymanagement.h"
  15. #include "keymanagement_internal.h"
  16. #include "KeySync_fsm.h"
  17. static bool key_matches_address(PEP_SESSION session, const char* address,
  18. const char* fpr) {
  19. if (!session || !address || !fpr)
  20. return false;
  21. bool retval = false;
  22. stringlist_t *keylist = NULL;
  23. PEP_STATUS status = find_keys(session, address, &keylist);
  24. if (status == PEP_STATUS_OK && keylist) {
  25. stringlist_t* curr = keylist;
  26. while (curr) {
  27. if (curr->value) {
  28. if (strcasecmp(curr->value, fpr)) {
  29. retval = true;
  30. break;
  31. }
  32. }
  33. curr = curr->next;
  34. }
  35. }
  36. free_stringlist(keylist);
  37. return retval;
  38. }
  39. // own_must_contain_private is usually true when calling;
  40. // we only set it to false when we have the idea of
  41. // possibly having an own pubkey that we need to check on its own
  42. // N.B. Checked for PASSPHRASE errors - will now return them always
  43. // False value of "renew_private" prevents their possibility, though.
  44. PEP_STATUS validate_fpr(PEP_SESSION session,
  45. pEp_identity* ident,
  46. bool own_must_contain_private,
  47. bool renew_private) {
  48. PEP_STATUS status = PEP_STATUS_OK;
  49. if (!session || !ident || !ident->fpr || !ident->fpr[0])
  50. return PEP_ILLEGAL_VALUE;
  51. char* fpr = ident->fpr;
  52. bool has_private = false;
  53. status = contains_priv_key(session, fpr, &has_private);
  54. // N.B. Will not contain PEP_PASSPHRASE related returns here
  55. if (ident->me && own_must_contain_private) {
  56. if (status != PEP_STATUS_OK || !has_private)
  57. return PEP_KEY_UNSUITABLE;
  58. }
  59. else if (status != PEP_STATUS_OK && has_private) // should never happen
  60. has_private = false;
  61. ident->comm_type = PEP_ct_unknown;
  62. status = get_trust(session, ident);
  63. if (status != PEP_STATUS_OK)
  64. ident->comm_type = PEP_ct_unknown;
  65. PEP_comm_type ct = ident->comm_type;
  66. if (ct == PEP_ct_unknown) {
  67. // If status is bad, it's ok, we get the rating
  68. // we should use then (PEP_ct_unknown).
  69. // Only one we really care about here is PEP_OUT_OF_MEMORY
  70. status = get_key_rating(session, fpr, &ct);
  71. if (status == PEP_OUT_OF_MEMORY)
  72. return PEP_OUT_OF_MEMORY;
  73. ident->comm_type = ct;
  74. }
  75. else if (ct == PEP_ct_key_expired || ct == PEP_ct_key_expired_but_confirmed) {
  76. PEP_comm_type ct_expire_check = PEP_ct_unknown;
  77. status = get_key_rating(session, fpr, &ct_expire_check);
  78. if (status == PEP_OUT_OF_MEMORY)
  79. return PEP_OUT_OF_MEMORY;
  80. if (ct_expire_check >= PEP_ct_strong_but_unconfirmed) {
  81. ident->comm_type = ct_expire_check;
  82. if (ct == PEP_ct_key_expired_but_confirmed)
  83. ident->comm_type |= PEP_ct_confirmed;
  84. ct = ident->comm_type;
  85. // We need to fix this trust in the DB.
  86. status = set_trust(session, ident);
  87. }
  88. }
  89. bool pEp_user = false;
  90. status = is_pEp_user(session, ident, &pEp_user);
  91. if (status == PEP_OUT_OF_MEMORY)
  92. return PEP_OUT_OF_MEMORY;
  93. if (pEp_user) {
  94. switch (ct) {
  95. case PEP_ct_OpenPGP:
  96. case PEP_ct_OpenPGP_unconfirmed:
  97. ct += 0x47; // difference between PEP and OpenPGP values;
  98. ident->comm_type = ct;
  99. break;
  100. default:
  101. break;
  102. }
  103. }
  104. bool revoked, expired;
  105. // Should not need to decrypt key material
  106. status = key_revoked(session, fpr, &revoked);
  107. if (status != PEP_STATUS_OK) {
  108. return status;
  109. }
  110. if (!revoked) {
  111. time_t exp_time = (ident->me ?
  112. time(NULL) + (7*24*3600) : time(NULL));
  113. // Should not need to decrypt key material
  114. status = key_expired(session, fpr,
  115. exp_time,
  116. &expired);
  117. assert(status == PEP_STATUS_OK);
  118. if (status != PEP_STATUS_OK)
  119. return status;
  120. }
  121. // Renew key if it's expired, our own, has a private part,
  122. // isn't too weak, and we didn't say "DON'T DO THIS"
  123. if (renew_private && ident->me && has_private &&
  124. (ct >= PEP_ct_strong_but_unconfirmed) &&
  125. !revoked && expired) {
  126. // extend key
  127. timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
  128. status = renew_key(session, fpr, ts);
  129. free_timestamp(ts);
  130. if (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE)
  131. return status;
  132. if (status == PEP_STATUS_OK) {
  133. // if key is valid (second check because pEp key might be extended above)
  134. // Return fpr
  135. status = key_expired(session, fpr, time(NULL), &expired);
  136. if (status != PEP_STATUS_OK)
  137. return status;
  138. if (expired) {
  139. if (ident->comm_type & PEP_ct_confirmed || (ident->comm_type == PEP_ct_key_expired_but_confirmed))
  140. ident->comm_type = PEP_ct_key_expired_but_confirmed;
  141. else
  142. ident->comm_type = PEP_ct_key_expired;
  143. return status;
  144. }
  145. // communicate key(?)
  146. }
  147. }
  148. if (revoked)
  149. ct = PEP_ct_key_revoked;
  150. else if (expired) {
  151. if (ident->comm_type & PEP_ct_confirmed || (ident->comm_type == PEP_ct_key_expired_but_confirmed))
  152. ct = PEP_ct_key_expired_but_confirmed;
  153. else
  154. ct = PEP_ct_key_expired;
  155. }
  156. switch (ct) {
  157. case PEP_ct_key_revoked:
  158. case PEP_ct_key_b0rken:
  159. // delete key from being default key for all users/identities
  160. status = remove_fpr_as_default(session, fpr);
  161. // fallthrough intentional!
  162. case PEP_ct_key_expired:
  163. case PEP_ct_key_expired_but_confirmed:
  164. // Note: we no longer remove expired keys as defaults; pEp users
  165. // will either send us an updated key or a key reset, and OpenPGP
  166. // users can either do the same or request a manual key reset.
  167. // We don't want to upset the automated updating of expired keys.
  168. status = update_trust_for_fpr(session,
  169. fpr,
  170. ct);
  171. case PEP_ct_mistrusted:
  172. free(ident->fpr);
  173. ident->fpr = NULL;
  174. ident->comm_type = ct;
  175. status = PEP_KEY_UNSUITABLE;
  176. default:
  177. break;
  178. }
  179. return status;
  180. }
  181. PEP_STATUS get_all_keys_for_user(PEP_SESSION session,
  182. const char* user_id,
  183. stringlist_t** keys) {
  184. if (!session || EMPTYSTR(user_id) || !keys)
  185. return PEP_ILLEGAL_VALUE;
  186. PEP_STATUS status = PEP_STATUS_OK;
  187. *keys = NULL;
  188. stringlist_t* _kl = NULL;
  189. sqlite3_reset(session->get_all_keys_for_user);
  190. sqlite3_bind_text(session->get_all_keys_for_user, 1, user_id, -1, SQLITE_STATIC);
  191. int result = -1;
  192. while ((result = sqlite3_step(session->get_all_keys_for_user)) == SQLITE_ROW) {
  193. const char* keyres = (const char *) sqlite3_column_text(session->get_all_keys_for_user, 0);
  194. if (keyres) {
  195. if (_kl)
  196. stringlist_add(_kl, keyres);
  197. else
  198. _kl = new_stringlist(keyres);
  199. }
  200. }
  201. if (!_kl)
  202. return PEP_KEY_NOT_FOUND;
  203. *keys = _kl;
  204. sqlite3_reset(session->get_all_keys_for_user);
  205. return status;
  206. }
  207. PEP_STATUS get_user_default_key(PEP_SESSION session, const char* user_id,
  208. char** default_key) {
  209. assert(session);
  210. assert(user_id);
  211. if (!session || !user_id)
  212. return PEP_ILLEGAL_VALUE;
  213. PEP_STATUS status = PEP_STATUS_OK;
  214. // try to get default key for user_data
  215. sqlite3_reset(session->get_user_default_key);
  216. sqlite3_bind_text(session->get_user_default_key, 1, user_id,
  217. -1, SQLITE_STATIC);
  218. const int result = sqlite3_step(session->get_user_default_key);
  219. char* user_fpr = NULL;
  220. if (result == SQLITE_ROW) {
  221. const char* u_fpr =
  222. (char *) sqlite3_column_text(session->get_user_default_key, 0);
  223. if (u_fpr)
  224. user_fpr = strdup(u_fpr);
  225. }
  226. else
  227. status = PEP_GET_KEY_FAILED;
  228. sqlite3_reset(session->get_user_default_key);
  229. *default_key = user_fpr;
  230. return status;
  231. }
  232. // Only call on retrieval of previously stored identity!
  233. // Also, we presume that if the stored_identity was sent in
  234. // without an fpr, there wasn't one in the trust DB for this
  235. // identity.
  236. //
  237. // Will now NOT return passphrase errors, as we tell
  238. // validate_fpr NOT to renew it. And we specifically suppress them
  239. // with "PEP_KEY_UNSUITABLE"
  240. //
  241. PEP_STATUS get_valid_pubkey(PEP_SESSION session,
  242. pEp_identity* stored_identity,
  243. bool* is_identity_default,
  244. bool* is_user_default,
  245. bool* is_address_default) {
  246. if (!session)
  247. return PEP_ILLEGAL_VALUE;
  248. PEP_STATUS status = PEP_STATUS_OK;
  249. if (!stored_identity || EMPTYSTR(stored_identity->user_id)
  250. || !is_identity_default || !is_user_default || !is_address_default)
  251. return PEP_ILLEGAL_VALUE;
  252. *is_identity_default = *is_user_default = *is_address_default = false;
  253. PEP_comm_type first_reject_comm_type = PEP_ct_key_not_found;
  254. PEP_STATUS first_reject_status = PEP_KEY_NOT_FOUND;
  255. char* stored_fpr = stored_identity->fpr;
  256. // Input: stored identity retrieved from database
  257. // if stored identity contains a default key; if so, we return from here
  258. if (!EMPTYSTR(stored_fpr)) {
  259. // Won't ask for passphrase, won't return PASSPHRASE status
  260. // Because of non-renewal
  261. status = validate_fpr(session, stored_identity, true, false);
  262. switch (status) {
  263. case PEP_STATUS_OK:
  264. if (!EMPTYSTR(stored_identity->fpr)) {
  265. *is_identity_default = *is_address_default = true;
  266. return status;
  267. }
  268. break;
  269. case PEP_KEY_NOT_FOUND:
  270. break;
  271. default:
  272. first_reject_status = status;
  273. first_reject_comm_type = stored_identity->comm_type;
  274. }
  275. }
  276. // if no valid default stored identity key found
  277. free(stored_identity->fpr);
  278. stored_identity->fpr = NULL;
  279. char* user_fpr = NULL;
  280. status = get_user_default_key(session, stored_identity->user_id, &user_fpr);
  281. if (!EMPTYSTR(user_fpr)) {
  282. // There exists a default key for user, so validate
  283. stored_identity->fpr = user_fpr;
  284. // Won't ask for passphrase, won't return PASSPHRASE status
  285. // Because of non-renewal
  286. status = validate_fpr(session, stored_identity, true, false);
  287. switch (status) {
  288. case PEP_STATUS_OK:
  289. if (!EMPTYSTR(stored_identity->fpr)) {
  290. *is_user_default = true;
  291. *is_address_default = key_matches_address(session,
  292. stored_identity->address,
  293. stored_identity->fpr);
  294. return status;
  295. }
  296. break;
  297. case PEP_KEY_NOT_FOUND:
  298. break;
  299. default:
  300. if (first_reject_status != PEP_KEY_NOT_FOUND) {
  301. first_reject_status = status;
  302. first_reject_comm_type = stored_identity->comm_type;
  303. }
  304. }
  305. }
  306. // If we got here, there's no usable default.
  307. switch (first_reject_comm_type) {
  308. case PEP_ct_key_revoked:
  309. case PEP_ct_key_b0rken:
  310. case PEP_ct_key_expired:
  311. case PEP_ct_key_expired_but_confirmed:
  312. case PEP_ct_compromised:
  313. case PEP_ct_mistrusted:
  314. // this only happens when it's all there is
  315. status = first_reject_status;
  316. free(stored_identity->fpr);
  317. stored_identity->fpr = NULL;
  318. stored_identity->comm_type = first_reject_comm_type;
  319. break;
  320. default:
  321. break;
  322. }
  323. // should never happen, but we will MAKE sure
  324. if (PASS_ERROR(status))
  325. status = PEP_KEY_UNSUITABLE; // renew it on your own time, baby
  326. return status;
  327. }
  328. /**
  329. * @internal
  330. *
  331. * <!-- transfer_ident_lang_and_flags() -->
  332. *
  333. * @brief TODO
  334. *
  335. * @param[in] *new_ident pEp_identity
  336. * @param[in] *stored_ident pEp_identity
  337. *
  338. */
  339. static void transfer_ident_lang_and_flags(pEp_identity* new_ident,
  340. pEp_identity* stored_ident) {
  341. if (!(new_ident && stored_ident))
  342. return;
  343. if (new_ident->lang[0] == 0) {
  344. new_ident->lang[0] = stored_ident->lang[0];
  345. new_ident->lang[1] = stored_ident->lang[1];
  346. new_ident->lang[2] = 0;
  347. }
  348. new_ident->flags = stored_ident->flags;
  349. new_ident->me = new_ident->me || stored_ident->me;
  350. }
  351. /**
  352. * @internal
  353. *
  354. * <!-- adjust_pEp_trust_status() -->
  355. *
  356. * @brief TODO
  357. *
  358. * @param[in] session session handle
  359. * @param[in] *identity pEp_identity
  360. *
  361. */
  362. static void adjust_pEp_trust_status(PEP_SESSION session, pEp_identity* identity) {
  363. assert(session);
  364. assert(identity);
  365. if (!session || !identity ||
  366. identity->comm_type < PEP_ct_strong_but_unconfirmed ||
  367. ((identity->comm_type | PEP_ct_confirmed) == PEP_ct_pEp) )
  368. return;
  369. bool pEp_user;
  370. is_pEp_user(session, identity, &pEp_user);
  371. if (pEp_user) {
  372. PEP_comm_type confirmation_status = identity->comm_type & PEP_ct_confirmed;
  373. identity->comm_type = PEP_ct_pEp_unconfirmed | confirmation_status;
  374. if (identity->major_ver == 0) {
  375. identity->major_ver = 2;
  376. identity->minor_ver = 1;
  377. }
  378. }
  379. }
  380. // NEVER called on an own identity.
  381. // But we also make sure get_valid_pubkey
  382. // and friends NEVER return with a password error.
  383. // (get_valid_pubkey tells validate_fpr not to try renewal)
  384. // Will not return PASSPHRASE errors.
  385. /**
  386. * @internal
  387. *
  388. * <!-- prepare_updated_identity() -->
  389. *
  390. * @brief TODO
  391. *
  392. * @param[in] session session handle
  393. * @param[in] *return_id pEp_identity
  394. * @param[in] *stored_ident pEp_identity
  395. * @param[in] store bool
  396. *
  397. * @retval PEP_STATUS_OK
  398. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  399. * @retval any other value on error
  400. */
  401. static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
  402. pEp_identity* return_id,
  403. pEp_identity* stored_ident,
  404. bool store) {
  405. if (!session || !return_id || !stored_ident)
  406. return PEP_ILLEGAL_VALUE;
  407. PEP_STATUS status;
  408. bool is_identity_default, is_user_default, is_address_default;
  409. bool no_stored_default = EMPTYSTR(stored_ident->fpr);
  410. status = get_valid_pubkey(session, stored_ident,
  411. &is_identity_default,
  412. &is_user_default,
  413. &is_address_default);
  414. bool is_pEp = false;
  415. switch (status) {
  416. // FIXME: can we get memory or DB errors from the above? If so, handle it.
  417. case PEP_STATUS_OK:
  418. if (!EMPTYSTR(stored_ident->fpr)) {
  419. // set identity comm_type from trust db (user_id, FPR)
  420. status = get_trust(session, stored_ident);
  421. PEP_comm_type ct = stored_ident->comm_type;
  422. if (status == PEP_CANNOT_FIND_IDENTITY || ct == PEP_ct_unknown || ct == PEP_ct_key_not_found) {
  423. // This is OK - there is no trust DB entry, but we
  424. // found a key. We won't store this, but we'll
  425. // use it.
  426. ct = PEP_ct_unknown;
  427. status = get_key_rating(session, stored_ident->fpr, &ct);
  428. stored_ident->comm_type = (ct == PEP_ct_unknown ? PEP_ct_key_not_found : ct);
  429. }
  430. }
  431. else if (stored_ident->comm_type == PEP_ct_unknown)
  432. stored_ident->comm_type = PEP_ct_key_not_found;
  433. break;
  434. case PEP_KEY_UNSUITABLE:
  435. status = PEP_STATUS_OK;
  436. // explicit fallthrough
  437. default:
  438. is_pEp_user(session, stored_ident, &is_pEp);
  439. if (is_pEp) {
  440. switch (stored_ident->comm_type) {
  441. case PEP_ct_key_expired:
  442. case PEP_ct_key_expired_but_confirmed:
  443. store = false;
  444. break;
  445. default:
  446. break;
  447. }
  448. }
  449. free(stored_ident->fpr);
  450. stored_ident->fpr = NULL;
  451. stored_ident->comm_type = PEP_ct_key_not_found;
  452. }
  453. free(return_id->fpr);
  454. return_id->fpr = NULL;
  455. if (status == PEP_STATUS_OK && !EMPTYSTR(stored_ident->fpr))
  456. return_id->fpr = strdup(stored_ident->fpr);
  457. return_id->comm_type = stored_ident->comm_type;
  458. // We patch the DB with the input username, but if we didn't have
  459. // one, we pull it out of storage if available.
  460. if (!EMPTYSTR(stored_ident->username)) {
  461. if (!EMPTYSTR(return_id->username) &&
  462. (strcasecmp(return_id->username, return_id->address) == 0)) {
  463. free(return_id->username);
  464. return_id->username = NULL;
  465. }
  466. if (EMPTYSTR(return_id->username)) {
  467. free(return_id->username);
  468. return_id->username = strdup(stored_ident->username);
  469. }
  470. }
  471. else {
  472. if (EMPTYSTR(return_id->username))
  473. return_id->username = strdup(return_id->address);
  474. }
  475. return_id->me = stored_ident->me;
  476. return_id->major_ver = stored_ident->major_ver;
  477. return_id->minor_ver = stored_ident->minor_ver;
  478. // FIXME: Do we ALWAYS do this? We probably should...
  479. if (EMPTYSTR(return_id->user_id)) {
  480. free(return_id->user_id);
  481. return_id->user_id = strdup(stored_ident->user_id);
  482. }
  483. adjust_pEp_trust_status(session, return_id);
  484. // Call set_identity() to store
  485. if (store && (is_identity_default || is_user_default) &&
  486. is_address_default) {
  487. // if we got an fpr which is default for either user
  488. // or identity AND is valid for this address, set in DB
  489. // as default
  490. status = set_identity(session, return_id);
  491. }
  492. else if (store && no_stored_default && !EMPTYSTR(return_id->fpr)
  493. && return_id->comm_type != PEP_ct_key_revoked
  494. && return_id->comm_type != PEP_ct_key_expired
  495. && return_id->comm_type != PEP_ct_key_expired_but_confirmed
  496. && return_id->comm_type != PEP_ct_mistrusted
  497. && return_id->comm_type != PEP_ct_key_b0rken) {
  498. // We would have stored this anyway for a first-time elected key. We just have an ident w/ no default already.
  499. status = set_identity(session, return_id);
  500. }
  501. else { // this is a key other than the default, but there IS a default (FIXME: fdik, do we really want behaviour below?)
  502. // Store without default fpr/ct, but return the fpr and ct
  503. // for current use
  504. char* save_fpr = return_id->fpr;
  505. PEP_comm_type save_ct = return_id->comm_type;
  506. return_id->fpr = NULL;
  507. return_id->comm_type = PEP_ct_unknown;
  508. if (store) {
  509. PEP_STATUS save_status = status;
  510. status = set_identity(session, return_id);
  511. if (save_status != PEP_STATUS_OK)
  512. status = save_status;
  513. }
  514. return_id->fpr = save_fpr;
  515. return_id->comm_type = save_ct;
  516. }
  517. transfer_ident_lang_and_flags(return_id, stored_ident);
  518. return_id->enc_format = stored_ident->enc_format;
  519. if (return_id->comm_type == PEP_ct_unknown)
  520. return_id->comm_type = PEP_ct_key_not_found;
  521. return status;
  522. }
  523. // Should not return PASSPHRASE errors because we force
  524. // calls that can cause key renewal not to.
  525. DYNAMIC_API PEP_STATUS update_identity(
  526. PEP_SESSION session, pEp_identity * identity
  527. )
  528. {
  529. PEP_STATUS status = PEP_STATUS_OK;
  530. assert(session);
  531. assert(identity);
  532. assert(!EMPTYSTR(identity->address));
  533. if (!(session && identity && !EMPTYSTR(identity->address)))
  534. return PEP_ILLEGAL_VALUE;
  535. //
  536. // Record some information about the input identity so that we don't keep
  537. // evaluating it
  538. //
  539. bool is_own_user = identity->me;
  540. bool input_has_user_id = !EMPTYSTR(identity->user_id);
  541. bool input_has_username = !EMPTYSTR(identity->username);
  542. bool input_has_real_id = input_has_user_id ? (strstr(identity->user_id, "TOFU_") != identity->user_id) : false;
  543. char* default_own_id = NULL;
  544. pEp_identity* stored_ident = NULL;
  545. status = get_default_own_userid(session, &default_own_id);
  546. if (status == PEP_STATUS_OK || status == PEP_CANNOT_FIND_IDENTITY)
  547. status = PEP_STATUS_OK;
  548. else
  549. goto pEp_free;
  550. // To be clear, if an own identity comes in here, the only way we will accept
  551. // it is if the caller did not KNOW this, as indicated by the lack of a known
  552. // own user_id and identity->me being false.
  553. //
  554. // IF either of these are set, then the call will fail. If, however, we get
  555. // an identity which simply has the own address on it, we'll kindly call a read-only
  556. // version of myself.
  557. if (!is_own_user) {
  558. if (default_own_id) {
  559. if (input_has_user_id) {
  560. if (strcmp(default_own_id, identity->user_id) == 0) {
  561. is_own_user = true;
  562. }
  563. else {
  564. char* alias = NULL;
  565. if (get_userid_alias_default(session, identity->user_id, &alias) == PEP_STATUS_OK) {
  566. if (alias && strcmp(default_own_id, alias) == 0)
  567. is_own_user = true;
  568. free(alias);
  569. }
  570. }
  571. }
  572. else {
  573. // Check if own address. For now, this is a special case;
  574. // we try to require apps to send in user_ids, but must prevent
  575. // writes to an own identity from within THIS function
  576. // NOTE: These semantics MAY CHANGE.
  577. bool _own_addr = false;
  578. is_own_address(session, identity->address, &_own_addr);
  579. if (_own_addr) {
  580. free(identity->user_id);
  581. // ENGINE-952: Ownership transfer. Allocated and checked above.
  582. identity->user_id = default_own_id;
  583. // Do not renew, do not generate
  584. return _myself(session, identity, false, false, false, true);
  585. }
  586. }
  587. }
  588. // Otherwise, we don't even HAVE an own user yet, so we're ok.
  589. }
  590. if (is_own_user) {
  591. free(default_own_id);
  592. return PEP_ILLEGAL_VALUE;
  593. }
  594. // We have, at least, an address.
  595. // Retrieve stored identity information!
  596. //////////////////////////////////////////////////////////////////////////////////////////////////////
  597. // If we can get a starting identity from the database, do it. If we have a user_id (thank you, users),
  598. // this is pretty simple.
  599. //
  600. // Otherwise, we double-check that someone didn't pass in an own address (hey, if you don't give us a
  601. // user_id, we're have to guess somehow, and treating own identities like partner identities is dangerous).
  602. //////////////////////////////////////////////////////////////////////////////////////////////////////
  603. if (input_has_user_id) {
  604. // (we're gonna update the trust/fpr anyway, so we use the no-fpr-from-trust-db variant)
  605. // * do get_identity() to retrieve stored identity information
  606. status = get_identity_without_trust_check(session, identity->address, identity->user_id, &stored_ident);
  607. }
  608. else { // see if we perhaps own this user
  609. if (default_own_id) {
  610. status = get_identity(session,
  611. identity->address,
  612. default_own_id,
  613. &stored_ident);
  614. }
  615. }
  616. //////////////////////////////////////////////////////////////////////////////////////////////////////
  617. // If we're unable to get a starting stored ID, we now need to try to get IDs which match the address.
  618. // Should we find them, we go through the list and try to find an acceptable one by evaluating the
  619. // following properties (not in order of priority, and not for every case - the logic here is a mess):
  620. //
  621. // 1. Did the input have a user_id?
  622. // 2. Did the input have a username? N.B. This is, as of ENGINE-828, less important than it was.
  623. // 3. Is the input user_id a real id?
  624. // 4. Is the stored user_id a real id?
  625. // 5. Does the stored user_id have a username?
  626. //
  627. // Based on this, if we find an acceptable candidate, we do one:
  628. //
  629. // 1. Replace the global DB user_id with the input user_id and patch the stored identity's user_id
  630. // (this may be different than 1, though in practice it seems we always do both)
  631. // 2. Patch the output identity's user_id from the stored identity
  632. //
  633. // If we find none, we'll try a TOFU id fetch before giving up on stored identity candidates.
  634. //
  635. // Acceptable candidates are then passed to prepare_update_identity which will patch usernames and
  636. // find any applicable keys.
  637. //
  638. // Unacceptable candidates will then have minimal record information entered depending on how much
  639. // came in in the input, TOFU user_ids created when needed, and a new record placed in the DB
  640. // accordingly.
  641. //
  642. if (!stored_ident) {
  643. identity_list* id_list = NULL;
  644. status = get_identities_by_address(session, identity->address, &id_list);
  645. if (id_list) {
  646. identity_list* stored_curr = id_list;
  647. // Ok, here's where we search for stored identities and try to find a candidate.
  648. while (stored_curr) {
  649. // Ok, this is where the above code fun begins. Let's get some information about the identity.
  650. pEp_identity* candidate = stored_curr->ident;
  651. if (candidate) {
  652. char* candidate_id = candidate->user_id;
  653. // this_uid should never be NULL, as this is half of the ident
  654. // DB primary key
  655. assert(!EMPTYSTR(candidate_id));
  656. // grab some information about the stored identity
  657. bool candidate_has_real_id = strstr(candidate_id, "TOFU_") != candidate_id;
  658. bool candidate_has_username = !EMPTYSTR(candidate->username);
  659. bool candidate_name_is_addr __attribute__((unused))
  660. = candidate_has_username ? strcmp(candidate->address, candidate->username) == 0 : false;
  661. // This is where the optimisation gets a little weird:
  662. //
  663. // Decide whether to accept and patch the database and stored id from the input,
  664. // Accept and patch the input id from the database, or reject and go to the next
  665. // one in the list
  666. //
  667. // This is unnecessary, but I think the terms need to be descriptive where possible
  668. bool input_addr_only = !input_has_username && !input_has_user_id;
  669. bool candidate_id_best = candidate_has_real_id && !input_has_real_id;
  670. bool input_id_best = input_has_real_id && !candidate_has_real_id;
  671. // bool patch_input_id_conditions = input_has_user_id || names_match || weak_candidate_name; // No longer necessary, as we don't compare usernames
  672. if (input_addr_only || candidate_id_best) {
  673. identity->user_id = strdup(candidate_id);
  674. assert(identity->user_id);
  675. if (!identity->user_id)
  676. goto enomem;
  677. stored_ident = identity_dup(candidate);
  678. break;
  679. }
  680. else if (input_id_best) {
  681. // Replace the TOFU db in the database with the input ID globally
  682. status = replace_userid(session,
  683. candidate_id,
  684. identity->user_id);
  685. if (status != PEP_STATUS_OK) {
  686. free_identity_list(id_list);
  687. free(default_own_id);
  688. return status;
  689. }
  690. // Reflect the change we just made to the DB
  691. free(candidate->user_id);
  692. candidate->user_id = strdup(identity->user_id);
  693. stored_ident = identity_dup(candidate);
  694. break;
  695. } // End else if
  696. // Else, we reject this candidate and try the next one, if there is one.
  697. // Remember, the "user_id"s match case was already taken care of by get_identity
  698. // above.
  699. stored_curr = stored_curr->next;
  700. }
  701. // Ok, we've checked all of the candidates, and if there's a stored identity, there's a duplicate.
  702. // Freeeeeeee...
  703. free_identity_list(id_list);
  704. }
  705. }
  706. // If, by here, there is no user id on the identity, we put one on there.
  707. // We've found any non-TOFU one we're going to find, so if this is empty,
  708. // We don't have a stored ident.
  709. if (EMPTYSTR(identity->user_id)) {
  710. identity->user_id = calloc(1, strlen(identity->address) + 6);
  711. if (!identity->user_id)
  712. goto enomem;
  713. snprintf(identity->user_id, strlen(identity->address) + 6,
  714. "TOFU_%s", identity->address);
  715. // Try one last time to see if there is an ident for us with a TOFU id
  716. //
  717. // We no longer use the username as a qualifying condition.
  718. //
  719. status = get_identity(session,
  720. identity->address,
  721. identity->user_id,
  722. &stored_ident);
  723. }
  724. }
  725. //
  726. // Either update the identity (and possibly DB to reflect stored ident information, or
  727. // create a new identity and store it.
  728. //
  729. if (status == PEP_STATUS_OK && stored_ident) {
  730. // An identity was available.
  731. // Call will patch the username where needed and
  732. // get a valid default key (for ident or user)
  733. status = prepare_updated_identity(session,
  734. identity,
  735. stored_ident, true);
  736. }
  737. else { // No stored ident. We're done.
  738. // If we needed TOFU, we've taken care of the ID above.
  739. if (EMPTYSTR(identity->username)) { // currently, not after messing around
  740. free(identity->username);
  741. identity->username = strdup(identity->address);
  742. if (!identity->username)
  743. goto enomem;
  744. }
  745. free(identity->fpr);
  746. identity->fpr = NULL;
  747. identity->comm_type = PEP_ct_unknown;
  748. adjust_pEp_trust_status(session, identity);
  749. status = set_identity(session, identity);
  750. // This is ONLY for the return value - VB confirms we should tell the user we didn't find a key
  751. if (identity->comm_type == PEP_ct_unknown)
  752. identity->comm_type = PEP_ct_key_not_found;
  753. }
  754. goto pEp_free;
  755. enomem:
  756. status = PEP_OUT_OF_MEMORY;
  757. pEp_free:
  758. free(default_own_id);
  759. free_identity(stored_ident);
  760. return status;
  761. }
  762. /**
  763. * @internal
  764. *
  765. * <!-- elect_ownkey() -->
  766. *
  767. * @brief TODO
  768. *
  769. * @param[in] session session handle
  770. * @param[in] *identity pEp_identity
  771. *
  772. * @retval PEP_STATUS_OK
  773. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  774. * @retval PEP_OUT_OF_MEMORY out of memory
  775. * @retval any other value on error
  776. */
  777. PEP_STATUS elect_ownkey(
  778. PEP_SESSION session, pEp_identity * identity
  779. )
  780. {
  781. if (!(session && identity))
  782. return PEP_ILLEGAL_VALUE;
  783. PEP_STATUS status;
  784. stringlist_t *keylist = NULL;
  785. free(identity->fpr);
  786. identity->fpr = NULL;
  787. status = find_private_keys(session, identity->address, &keylist);
  788. assert(status != PEP_OUT_OF_MEMORY);
  789. if (status == PEP_OUT_OF_MEMORY)
  790. return PEP_OUT_OF_MEMORY;
  791. if (keylist != NULL && keylist->value != NULL)
  792. {
  793. char *_fpr = NULL;
  794. identity->comm_type = PEP_ct_unknown;
  795. stringlist_t *_keylist;
  796. for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
  797. bool is_own = false;
  798. status = own_key_is_listed(session, _keylist->value, &is_own);
  799. assert(status == PEP_STATUS_OK);
  800. if (status != PEP_STATUS_OK) {
  801. free_stringlist(keylist);
  802. return status;
  803. }
  804. if (is_own)
  805. {
  806. PEP_comm_type _comm_type_key;
  807. status = get_key_rating(session, _keylist->value, &_comm_type_key);
  808. assert(status != PEP_OUT_OF_MEMORY);
  809. if (status == PEP_OUT_OF_MEMORY) {
  810. free_stringlist(keylist);
  811. return PEP_OUT_OF_MEMORY;
  812. }
  813. if (_comm_type_key != PEP_ct_compromised &&
  814. _comm_type_key != PEP_ct_unknown)
  815. {
  816. if (identity->comm_type == PEP_ct_unknown ||
  817. _comm_type_key > identity->comm_type)
  818. {
  819. identity->comm_type = _comm_type_key;
  820. _fpr = _keylist->value;
  821. }
  822. }
  823. }
  824. }
  825. if (_fpr)
  826. {
  827. identity->fpr = strdup(_fpr);
  828. assert(identity->fpr);
  829. if (identity->fpr == NULL)
  830. {
  831. free_stringlist(keylist);
  832. return PEP_OUT_OF_MEMORY;
  833. }
  834. }
  835. free_stringlist(keylist);
  836. }
  837. return PEP_STATUS_OK;
  838. }
  839. /**
  840. * @internal
  841. *
  842. * <!-- _has_usable_priv_key() -->
  843. *
  844. * @brief TODO
  845. *
  846. * @param[in] session session handle
  847. * @param[in] *fpr char
  848. * @param[in] *is_usable bool
  849. *
  850. * @retval PEP_STATUS_OK
  851. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  852. * @retval any other value on error
  853. */
  854. PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
  855. bool* is_usable) {
  856. bool has_private = false;
  857. PEP_STATUS status = contains_priv_key(session, fpr, &has_private);
  858. *is_usable = has_private;
  859. return status;
  860. }
  861. PEP_STATUS _myself(PEP_SESSION session,
  862. pEp_identity * identity,
  863. bool do_keygen,
  864. bool do_renew,
  865. bool ignore_flags,
  866. bool read_only)
  867. {
  868. PEP_STATUS status;
  869. assert(session);
  870. assert(identity);
  871. assert(!EMPTYSTR(identity->address));
  872. if (!session || !identity || EMPTYSTR(identity->address))
  873. return PEP_ILLEGAL_VALUE;
  874. // this leads to crashes otherwise
  875. if (EMPTYSTR(identity->user_id)) {
  876. free(identity->user_id);
  877. identity->user_id = strdup(PEP_OWN_USERID);
  878. assert(identity->user_id);
  879. if (!identity->user_id)
  880. return PEP_OUT_OF_MEMORY;
  881. }
  882. // Cache the input username, if there is one and it's not read_only; NULL
  883. // otherwise. cached_input_username is never a pointer to an empty string.
  884. char* cached_input_username = NULL;
  885. if (!read_only && ! EMPTYSTR(identity->username)) {
  886. cached_input_username = strdup(identity->username);
  887. if (!cached_input_username)
  888. return PEP_OUT_OF_MEMORY;
  889. }
  890. pEp_identity *stored_identity = NULL;
  891. char* revoked_fpr = NULL;
  892. bool valid_key_found = false;
  893. char* default_own_id = NULL;
  894. status = get_default_own_userid(session, &default_own_id);
  895. // Deal with non-default user_ids.
  896. // FIXME: if non-default and read-only, reject totally?
  897. if (default_own_id && strcmp(default_own_id, identity->user_id) != 0) {
  898. if (read_only) {
  899. free(identity->user_id);
  900. identity->user_id = strdup(default_own_id);
  901. assert(identity->user_id);
  902. if (!identity->user_id)
  903. return PEP_OUT_OF_MEMORY;
  904. }
  905. else {
  906. status = set_userid_alias(session, default_own_id, identity->user_id);
  907. // Do we want this to be fatal? For now, we'll do it...
  908. if (status != PEP_STATUS_OK)
  909. goto pEp_free;
  910. free(identity->user_id);
  911. identity->user_id = strdup(default_own_id);
  912. assert(identity->user_id);
  913. if (identity->user_id == NULL) {
  914. status = PEP_OUT_OF_MEMORY;
  915. goto pEp_free;
  916. }
  917. }
  918. }
  919. // NOTE: IF WE DON'T YET HAVE AN OWN_ID, WE IGNORE REFERENCES TO THIS ADDRESS IN THE
  920. // DB (WHICH MAY HAVE BEEN SET BEFORE MYSELF WAS CALLED BY RECEIVING AN EMAIL FROM
  921. // THIS ADDRESS), AS IT IS NOT AN OWN_IDENTITY AND HAS NO INFORMATION WE NEED OR WHAT TO
  922. // SET FOR MYSELF
  923. // Ok, so now, set up the own_identity:
  924. identity->comm_type = PEP_ct_pEp;
  925. identity->me = true;
  926. if(ignore_flags)
  927. identity->flags = 0;
  928. // Let's see if we have an identity record in the DB for
  929. // this user_id + address
  930. // DEBUG_LOG("myself", "debug", identity->address);
  931. // This will grab the actual flags from the db
  932. status = get_identity(session,
  933. identity->address,
  934. identity->user_id,
  935. &stored_identity);
  936. assert(status != PEP_OUT_OF_MEMORY);
  937. if (status == PEP_OUT_OF_MEMORY) {
  938. status = PEP_OUT_OF_MEMORY;
  939. goto pEp_free;
  940. }
  941. // Set usernames - priority is input username > stored name > address
  942. // If there's an input username, we always patch the username with that
  943. // input.
  944. // N.B. there was an || read_only here, but why? read_only ONLY means
  945. // we don't write to the DB! So... removed. But how this managed to work
  946. // before I don't know.
  947. if (EMPTYSTR(identity->username)) {
  948. bool stored_uname = (stored_identity && !EMPTYSTR(stored_identity->username));
  949. char* uname = (stored_uname ? stored_identity->username : identity->address);
  950. if (uname) {
  951. free(identity->username);
  952. identity->username = strdup(uname);
  953. assert(identity->username);
  954. if (identity->username == NULL) {
  955. status = PEP_OUT_OF_MEMORY;
  956. goto pEp_free;
  957. }
  958. }
  959. }
  960. // ignore input fpr
  961. if (identity->fpr) {
  962. free(identity->fpr);
  963. identity->fpr = NULL;
  964. }
  965. // check stored identity
  966. if (stored_identity) {
  967. if (!EMPTYSTR(stored_identity->fpr)) {
  968. // Fall back / retrieve
  969. status = validate_fpr(session, stored_identity, true, do_renew);
  970. switch (status) {
  971. // Only possible if we called this with do_renew = true
  972. case PEP_OUT_OF_MEMORY:
  973. case PEP_PASSPHRASE_REQUIRED:
  974. case PEP_WRONG_PASSPHRASE:
  975. goto pEp_free;
  976. case PEP_STATUS_OK:
  977. if (stored_identity->comm_type >= PEP_ct_strong_but_unconfirmed) {
  978. identity->fpr = strdup(stored_identity->fpr);
  979. assert(identity->fpr);
  980. if (!identity->fpr) {
  981. status = PEP_OUT_OF_MEMORY;
  982. goto pEp_free;
  983. }
  984. valid_key_found = true;
  985. }
  986. else {
  987. bool revoked = false;
  988. status = key_revoked(session, stored_identity->fpr, &revoked);
  989. if (status)
  990. goto pEp_free;
  991. if (revoked) {
  992. revoked_fpr = strdup(stored_identity->fpr);
  993. assert(revoked_fpr);
  994. if (!revoked_fpr) {
  995. status = PEP_OUT_OF_MEMORY;
  996. goto pEp_free;
  997. }
  998. }
  999. }
  1000. break;
  1001. default:
  1002. break;
  1003. }
  1004. }
  1005. // reconcile language, flags
  1006. transfer_ident_lang_and_flags(identity, stored_identity);
  1007. }
  1008. // Nothing left to do but generate a key
  1009. if (!valid_key_found) {
  1010. if (!do_keygen || read_only)
  1011. status = PEP_GET_KEY_FAILED;
  1012. else {
  1013. // / DEBUG_LOG("Generating key pair", "debug", identity->address);
  1014. free(identity->fpr);
  1015. identity->fpr = NULL;
  1016. status = generate_keypair(session, identity);
  1017. assert(status != PEP_OUT_OF_MEMORY);
  1018. if (status == PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED)
  1019. goto pEp_free;
  1020. if (status != PEP_STATUS_OK) {
  1021. char buf[11];
  1022. snprintf(buf, 11, "%d", status); // uh, this is kludgey. FIXME
  1023. // DEBUG_LOG("Generating key pair failed", "debug", buf);
  1024. }
  1025. else {
  1026. valid_key_found = true;
  1027. if (revoked_fpr) {
  1028. status = set_revoked(session, revoked_fpr,
  1029. stored_identity->fpr, time(NULL));
  1030. assert(status == PEP_STATUS_OK);
  1031. }
  1032. }
  1033. }
  1034. }
  1035. if (valid_key_found) {
  1036. identity->comm_type = PEP_ct_pEp;
  1037. status = PEP_STATUS_OK;
  1038. }
  1039. else {
  1040. free(identity->fpr);
  1041. identity->fpr = NULL;
  1042. identity->comm_type = PEP_ct_unknown;
  1043. }
  1044. unsigned int major_ver = 0;
  1045. unsigned int minor_ver = 0;
  1046. pEp_version_major_minor(PEP_VERSION, &major_ver, &minor_ver);
  1047. identity->major_ver = major_ver;
  1048. identity->minor_ver = minor_ver;
  1049. // We want to set an identity in the DB even if a key isn't found, but we have to preserve the status if
  1050. // it's NOT ok
  1051. if (!read_only) {
  1052. // set identity will not automatically set identity.username in the database, only
  1053. // the person.username (user default). So we set it here, but will then force-set the name again if we
  1054. // have to.
  1055. PEP_STATUS set_id_status = set_identity(session, identity);
  1056. if (set_id_status == PEP_STATUS_OK)
  1057. set_id_status = set_as_pEp_user(session, identity);
  1058. if (set_id_status == PEP_STATUS_OK && cached_input_username) {
  1059. // Force-set input username
  1060. set_id_status = force_set_identity_username(session, identity, cached_input_username);
  1061. free(identity->username);
  1062. identity->username = cached_input_username;
  1063. cached_input_username = NULL;
  1064. }
  1065. status = (status == PEP_STATUS_OK ? set_id_status : status);
  1066. }
  1067. pEp_free:
  1068. free(default_own_id);
  1069. free(revoked_fpr);
  1070. free_identity(stored_identity);
  1071. free(cached_input_username);
  1072. return status;
  1073. }
  1074. DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
  1075. {
  1076. return _myself(session, identity, true, true, false, false);
  1077. }
  1078. DYNAMIC_API PEP_STATUS key_mistrusted(
  1079. PEP_SESSION session,
  1080. pEp_identity *ident
  1081. )
  1082. {
  1083. PEP_STATUS status = PEP_STATUS_OK;
  1084. assert(session);
  1085. assert(ident);
  1086. assert(!EMPTYSTR(ident->fpr));
  1087. if (!(session && ident && ident->fpr))
  1088. return PEP_ILLEGAL_VALUE;
  1089. bool has_private = false;
  1090. status = contains_priv_key(session, ident->fpr, &has_private);
  1091. if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
  1092. return status;
  1093. // See if key is revoked already
  1094. if (has_private) {
  1095. bool revoked = false;
  1096. status = key_revoked(session, ident->fpr, &revoked);
  1097. if (!revoked)
  1098. revoke_key(session, ident->fpr, NULL);
  1099. }
  1100. else {
  1101. if (ident->fpr) {
  1102. // Make sure there was a default in the DB for this identity;
  1103. // if not, set one, even though we're going to mistrust this. Otherwise,
  1104. // cannot reset.
  1105. pEp_identity* stored_ident = NULL;
  1106. get_identity(session, ident->address, ident->user_id, &stored_ident);
  1107. bool set_in_db = true;
  1108. if (!stored_ident)
  1109. stored_ident = identity_dup(ident);
  1110. else if (!stored_ident->fpr)
  1111. stored_ident->fpr = strdup(ident->fpr);
  1112. else
  1113. set_in_db = false;
  1114. if (set_in_db)
  1115. status = set_identity(session, stored_ident);
  1116. free_identity(stored_ident);
  1117. if (status != PEP_STATUS_OK)
  1118. return status;
  1119. }
  1120. }
  1121. // double-check to be sure key is even in the DB
  1122. if (ident->fpr)
  1123. status = set_pgp_keypair(session, ident->fpr);
  1124. // We set this temporarily but will grab it back from the cache afterwards
  1125. ident->comm_type = PEP_ct_mistrusted;
  1126. status = set_trust(session, ident);
  1127. if (status == PEP_STATUS_OK)
  1128. // cascade that mistrust for anyone using this key
  1129. status = mark_as_compromised(session, ident->fpr);
  1130. if (status == PEP_STATUS_OK)
  1131. status = add_mistrusted_key(session, ident->fpr);
  1132. return status;
  1133. }
  1134. DYNAMIC_API PEP_STATUS key_reset_trust(
  1135. PEP_SESSION session,
  1136. pEp_identity *ident
  1137. )
  1138. {
  1139. PEP_STATUS status = PEP_STATUS_OK;
  1140. assert(session);
  1141. assert(ident);
  1142. assert(!EMPTYSTR(ident->fpr));
  1143. assert(!EMPTYSTR(ident->address));
  1144. assert(!EMPTYSTR(ident->user_id));
  1145. if (!(session && ident && ident->fpr && ident->fpr[0] != '\0' && ident->address &&
  1146. ident->user_id))
  1147. return PEP_ILLEGAL_VALUE;
  1148. // we do not change the input struct at ALL.
  1149. pEp_identity* input_copy = identity_dup(ident);
  1150. pEp_identity* tmp_ident = NULL;
  1151. status = get_trust(session, input_copy);
  1152. if (status != PEP_STATUS_OK)
  1153. goto pEp_free;
  1154. PEP_comm_type new_trust = PEP_ct_unknown;
  1155. status = get_key_rating(session, ident->fpr, &new_trust);
  1156. if (status != PEP_STATUS_OK)
  1157. goto pEp_free;
  1158. bool pEp_user = false;
  1159. status = is_pEp_user(session, ident, &pEp_user);
  1160. if (pEp_user && new_trust >= PEP_ct_unconfirmed_encryption)
  1161. input_copy->comm_type = PEP_ct_pEp_unconfirmed;
  1162. else
  1163. input_copy->comm_type = new_trust;
  1164. status = set_trust(session, input_copy);
  1165. if (status != PEP_STATUS_OK)
  1166. goto pEp_free;
  1167. bool mistrusted_key = false;
  1168. status = is_mistrusted_key(session, ident->fpr, &mistrusted_key);
  1169. if (status != PEP_STATUS_OK)
  1170. goto pEp_free;
  1171. if (mistrusted_key)
  1172. status = delete_mistrusted_key(session, ident->fpr);
  1173. if (status != PEP_STATUS_OK)
  1174. goto pEp_free;
  1175. tmp_ident = new_identity(ident->address, NULL, ident->user_id, NULL);
  1176. if (!tmp_ident)
  1177. return PEP_OUT_OF_MEMORY;
  1178. if (is_me(session, tmp_ident))
  1179. status = myself(session, tmp_ident);
  1180. else
  1181. status = update_identity(session, tmp_ident);
  1182. if (status != PEP_STATUS_OK)
  1183. goto pEp_free;
  1184. // remove as default if necessary
  1185. if (!EMPTYSTR(tmp_ident->fpr) && strcmp(tmp_ident->fpr, ident->fpr) == 0) {
  1186. free(tmp_ident->fpr);
  1187. tmp_ident->fpr = NULL;
  1188. tmp_ident->comm_type = PEP_ct_unknown;
  1189. status = set_identity(session, tmp_ident);
  1190. if (status != PEP_STATUS_OK)
  1191. goto pEp_free;
  1192. }
  1193. char* user_default = NULL;
  1194. get_main_user_fpr(session, tmp_ident->user_id, &user_default);
  1195. if (!EMPTYSTR(user_default)) {
  1196. if (strcmp(user_default, ident->fpr) == 0)
  1197. status = refresh_userid_default_key(session, ident->user_id);
  1198. if (status != PEP_STATUS_OK)
  1199. goto pEp_free;
  1200. }
  1201. pEp_free:
  1202. free_identity(tmp_ident);
  1203. free_identity(input_copy);
  1204. return status;
  1205. }
  1206. // Technically speaking, this should not EVER
  1207. // return PASSPHRASE errors, because
  1208. // this is never for an own identity (enforced), and thus
  1209. // validate_fpr will not call renew_key.
  1210. // If it ever does, the status gets propagated, but
  1211. // it is distinctly not OK.
  1212. DYNAMIC_API PEP_STATUS trust_personal_key(
  1213. PEP_SESSION session,
  1214. pEp_identity *ident
  1215. )
  1216. {
  1217. PEP_STATUS status = PEP_STATUS_OK;
  1218. assert(session);
  1219. assert(ident);
  1220. assert(!EMPTYSTR(ident->address));
  1221. assert(!EMPTYSTR(ident->user_id));
  1222. assert(!EMPTYSTR(ident->fpr));
  1223. if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  1224. EMPTYSTR(ident->fpr))
  1225. return PEP_ILLEGAL_VALUE;
  1226. if (is_me(session, ident))
  1227. return PEP_ILLEGAL_VALUE;
  1228. char* ident_default_fpr = NULL;
  1229. // Before we do anything, be sure the input fpr is even eligible to be trusted
  1230. PEP_comm_type input_default_ct = PEP_ct_unknown;
  1231. status = get_key_rating(session, ident->fpr, &input_default_ct);
  1232. if (input_default_ct < PEP_ct_strong_but_unconfirmed)
  1233. return PEP_KEY_UNSUITABLE;
  1234. status = set_pgp_keypair(session, ident->fpr);
  1235. if (status != PEP_STATUS_OK)
  1236. return status;
  1237. pEp_identity* ident_copy = identity_dup(ident);
  1238. char* cached_fpr = NULL;
  1239. // for setting up a temp trusted identity for the input fpr
  1240. pEp_identity* tmp_id = NULL;
  1241. // For later, in case we need to check the user default key
  1242. pEp_identity* tmp_user_ident = NULL;
  1243. // Save the input fpr, which we already tested as non-NULL
  1244. cached_fpr = strdup(ident->fpr);
  1245. // Set up a temp trusted identity for the input fpr without a comm type;
  1246. tmp_id = new_identity(ident->address, ident->fpr, ident->user_id, NULL);
  1247. status = validate_fpr(session, tmp_id, true, false);
  1248. if (status == PEP_STATUS_OK) {
  1249. // Validate fpr gets trust DB or, when that fails, key comm type. we checked
  1250. // above that the key was ok. (not revoked or expired), but we want the max.
  1251. tmp_id->comm_type = _MAX(tmp_id->comm_type, input_default_ct) | PEP_ct_confirmed;
  1252. // Get the default identity without setting the fpr
  1253. status = update_identity(session, ident_copy);
  1254. ident_default_fpr = (EMPTYSTR(ident_copy->fpr) ? NULL : strdup(ident_copy->fpr));
  1255. if (status == PEP_STATUS_OK) {
  1256. bool trusted_default = false;
  1257. // If there's no default, or the default is different from the input...
  1258. if (EMPTYSTR(ident_default_fpr) || strcmp(cached_fpr, ident_default_fpr) != 0) {
  1259. // If the default fpr (if there is one) is trusted and key is strong enough,
  1260. // don't replace, we just set the trusted bit on this key for this user_id...
  1261. // (If there's no default fpr, this won't be true anyway.)
  1262. if ((ident_copy->comm_type >= PEP_ct_strong_but_unconfirmed &&
  1263. (ident_copy->comm_type & PEP_ct_confirmed))) {
  1264. trusted_default = true;
  1265. status = set_trust(session, tmp_id);
  1266. input_default_ct = tmp_id->comm_type;
  1267. }
  1268. else {
  1269. free(ident_copy->fpr);
  1270. ident_copy->fpr = strdup(cached_fpr);
  1271. ident_copy->comm_type = tmp_id->comm_type;
  1272. status = set_identity(session, ident_copy); // replace identity default
  1273. if (status == PEP_STATUS_OK) {
  1274. if ((ident_copy->comm_type | PEP_ct_confirmed) == PEP_ct_pEp)
  1275. status = set_as_pEp_user(session, ident_copy);
  1276. }
  1277. }
  1278. }
  1279. else { // we're setting this on the default fpr
  1280. ident->comm_type = tmp_id->comm_type;
  1281. status = set_identity(session, ident);
  1282. trusted_default = true;
  1283. }
  1284. if (status == PEP_STATUS_OK && !trusted_default) {
  1285. // Ok, there wasn't a trusted default, so we replaced. Thus, we also
  1286. // make sure there's a trusted default on the user_id. If there
  1287. // is not, we make this the default.
  1288. char* user_default = NULL;
  1289. status = get_main_user_fpr(session, ident->user_id, &user_default);
  1290. if (status == PEP_STATUS_OK && user_default) {
  1291. tmp_user_ident = new_identity(ident->address,
  1292. user_default,
  1293. ident->user_id,
  1294. NULL);
  1295. if (!tmp_user_ident)
  1296. status = PEP_OUT_OF_MEMORY;
  1297. else {
  1298. status = validate_fpr(session, tmp_user_ident, true, false);
  1299. if (status != PEP_STATUS_OK ||
  1300. tmp_user_ident->comm_type < PEP_ct_strong_but_unconfirmed ||
  1301. !(tmp_user_ident->comm_type & PEP_ct_confirmed))
  1302. {
  1303. char* trusted_fpr = (trusted_default ? ident_default_fpr : cached_fpr);
  1304. status = replace_main_user_fpr(session, ident->user_id, trusted_fpr);
  1305. }
  1306. }
  1307. }
  1308. }
  1309. }
  1310. }
  1311. free(ident_default_fpr);
  1312. free(cached_fpr);
  1313. free_identity(tmp_id);
  1314. free_identity(ident_copy);
  1315. free_identity(tmp_user_ident);
  1316. return status;
  1317. }
  1318. DYNAMIC_API PEP_STATUS trust_own_key(
  1319. PEP_SESSION session,
  1320. pEp_identity* ident
  1321. )
  1322. {
  1323. assert(session);
  1324. assert(ident);
  1325. assert(!EMPTYSTR(ident->address));
  1326. assert(!EMPTYSTR(ident->user_id));
  1327. assert(!EMPTYSTR(ident->fpr));
  1328. if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  1329. EMPTYSTR(ident->fpr))
  1330. return PEP_ILLEGAL_VALUE;
  1331. if (!is_me(session, ident))
  1332. return PEP_ILLEGAL_VALUE;
  1333. // don't require a private key
  1334. PEP_STATUS status = validate_fpr(session, ident, false, true);
  1335. if (status != PEP_STATUS_OK)
  1336. return status;
  1337. status = set_pgp_keypair(session, ident->fpr);
  1338. if (status != PEP_STATUS_OK)
  1339. return status;
  1340. if (ident->comm_type < PEP_ct_strong_but_unconfirmed)
  1341. return PEP_KEY_UNSUITABLE;
  1342. ident->comm_type |= PEP_ct_confirmed;
  1343. status = set_trust(session, ident);
  1344. return status;
  1345. }
  1346. DYNAMIC_API PEP_STATUS own_key_is_listed(
  1347. PEP_SESSION session,
  1348. const char *fpr,
  1349. bool *listed
  1350. )
  1351. {
  1352. PEP_STATUS status = PEP_STATUS_OK;
  1353. int count;
  1354. assert(session && fpr && fpr[0] && listed);
  1355. if (!(session && fpr && fpr[0] && listed))
  1356. return PEP_ILLEGAL_VALUE;
  1357. *listed = false;
  1358. sqlite3_reset(session->own_key_is_listed);
  1359. sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
  1360. int result;
  1361. result = sqlite3_step(session->own_key_is_listed);
  1362. switch (result) {
  1363. case SQLITE_ROW:
  1364. count = sqlite3_column_int(session->own_key_is_listed, 0);
  1365. *listed = count > 0;
  1366. status = PEP_STATUS_OK;
  1367. break;
  1368. default:
  1369. status = PEP_UNKNOWN_ERROR;
  1370. }
  1371. sqlite3_reset(session->own_key_is_listed);
  1372. return status;
  1373. }
  1374. PEP_STATUS _own_identities_retrieve(
  1375. PEP_SESSION session,
  1376. identity_list **own_identities,
  1377. identity_flags_t excluded_flags
  1378. )
  1379. {
  1380. PEP_STATUS status = PEP_STATUS_OK;
  1381. assert(session && own_identities);
  1382. if (!(session && own_identities))
  1383. return PEP_ILLEGAL_VALUE;
  1384. *own_identities = NULL;
  1385. identity_list *_own_identities = new_identity_list(NULL);
  1386. if (_own_identities == NULL)
  1387. goto enomem;
  1388. sqlite3_reset(session->own_identities_retrieve);
  1389. int result;
  1390. // address, fpr, username, user_id, comm_type, lang, flags
  1391. const char *address = NULL;
  1392. const char *fpr = NULL;
  1393. const char *username = NULL;
  1394. const char *user_id = NULL;
  1395. PEP_comm_type comm_type = PEP_ct_unknown;
  1396. const char *lang = NULL;
  1397. unsigned int flags = 0;
  1398. identity_list *_bl = _own_identities;
  1399. sqlite3_bind_int(session->own_identities_retrieve, 1, excluded_flags);
  1400. do {
  1401. result = sqlite3_step(session->own_identities_retrieve);
  1402. switch (result) {
  1403. case SQLITE_ROW:
  1404. address = (const char *)
  1405. sqlite3_column_text(session->own_identities_retrieve, 0);
  1406. fpr = (const char *)
  1407. sqlite3_column_text(session->own_identities_retrieve, 1);
  1408. user_id = (const char *)
  1409. sqlite3_column_text(session->own_identities_retrieve, 2);
  1410. username = (const char *)
  1411. sqlite3_column_text(session->own_identities_retrieve, 3);
  1412. comm_type = PEP_ct_pEp;
  1413. lang = (const char *)
  1414. sqlite3_column_text(session->own_identities_retrieve, 4);
  1415. flags = (unsigned int)
  1416. sqlite3_column_int(session->own_identities_retrieve, 5);
  1417. pEp_identity *ident = new_identity(address, fpr, user_id, username);
  1418. if (!ident)
  1419. goto enomem;
  1420. ident->comm_type = comm_type;
  1421. if (lang && lang[0]) {
  1422. ident->lang[0] = lang[0];
  1423. ident->lang[1] = lang[1];
  1424. ident->lang[2] = 0;
  1425. }
  1426. ident->me = true;
  1427. ident->flags = flags;
  1428. _bl = identity_list_add(_bl, ident);
  1429. if (_bl == NULL) {
  1430. free_identity(ident);
  1431. goto enomem;
  1432. }
  1433. break;
  1434. case SQLITE_DONE:
  1435. break;
  1436. default:
  1437. status = PEP_UNKNOWN_ERROR;
  1438. result = SQLITE_DONE;
  1439. }
  1440. } while (result != SQLITE_DONE);
  1441. sqlite3_reset(session->own_identities_retrieve);
  1442. if (status == PEP_STATUS_OK)
  1443. *own_identities = _own_identities;
  1444. else
  1445. free_identity_list(_own_identities);
  1446. goto the_end;
  1447. enomem:
  1448. free_identity_list(_own_identities);
  1449. status = PEP_OUT_OF_MEMORY;
  1450. the_end:
  1451. return status;
  1452. }
  1453. DYNAMIC_API PEP_STATUS own_identities_retrieve(
  1454. PEP_SESSION session,
  1455. identity_list **own_identities
  1456. )
  1457. {
  1458. return _own_identities_retrieve(session, own_identities, 0);
  1459. }
  1460. PEP_STATUS _own_keys_retrieve(
  1461. PEP_SESSION session,
  1462. stringlist_t **keylist,
  1463. identity_flags_t excluded_flags,
  1464. bool private_only
  1465. )
  1466. {
  1467. PEP_STATUS status = PEP_STATUS_OK;
  1468. assert(session && keylist);
  1469. if (!(session && keylist))
  1470. return PEP_ILLEGAL_VALUE;
  1471. *keylist = NULL;
  1472. stringlist_t *_keylist = NULL;
  1473. sqlite3_reset(session->own_keys_retrieve);
  1474. int result;
  1475. stringlist_t *_bl = _keylist;
  1476. sqlite3_bind_int(session->own_keys_retrieve, 1, excluded_flags);
  1477. do {
  1478. result = sqlite3_step(session->own_keys_retrieve);
  1479. switch (result) {
  1480. case SQLITE_ROW:
  1481. _bl = stringlist_add(_bl, (const char *)
  1482. sqlite3_column_text(session->own_keys_retrieve, 0));
  1483. if (_bl == NULL)
  1484. goto enomem;
  1485. if (_keylist == NULL)
  1486. _keylist = _bl;
  1487. break;
  1488. case SQLITE_DONE:
  1489. break;
  1490. default:
  1491. status = PEP_UNKNOWN_ERROR;
  1492. result = SQLITE_DONE;
  1493. }
  1494. } while (result != SQLITE_DONE);
  1495. sqlite3_reset(session->own_keys_retrieve);
  1496. if (status == PEP_STATUS_OK) {
  1497. dedup_stringlist(_keylist);
  1498. if (private_only) {
  1499. stringlist_t* _kl = _keylist;
  1500. stringlist_t* _kl_prev = NULL;
  1501. while (_kl) {
  1502. bool has_private = false;
  1503. contains_priv_key(session, _kl->value, &has_private);
  1504. if (!has_private) {
  1505. stringlist_t* _kl_tmp = _kl;
  1506. if (_kl_prev)
  1507. _kl_prev->next = _kl->next;
  1508. else
  1509. _keylist = _kl->next;
  1510. _kl = _kl->next;
  1511. _kl_tmp->next = NULL;
  1512. free_stringlist(_kl_tmp);
  1513. continue;
  1514. }
  1515. _kl_prev = _kl;
  1516. _kl = _kl->next;
  1517. }
  1518. }
  1519. *keylist = _keylist;
  1520. }
  1521. else
  1522. free_stringlist(_keylist);
  1523. goto the_end;
  1524. enomem:
  1525. free_stringlist(_keylist);
  1526. status = PEP_OUT_OF_MEMORY;
  1527. the_end:
  1528. return status;
  1529. }
  1530. DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **keylist)
  1531. {
  1532. return _own_keys_retrieve(session, keylist, 0, true);
  1533. }
  1534. PEP_STATUS update_key_sticky_bit_for_user(PEP_SESSION session,
  1535. pEp_identity* ident,
  1536. const char* fpr,
  1537. bool sticky) {
  1538. if (!session || !ident || EMPTYSTR(ident->user_id) || EMPTYSTR(fpr))
  1539. return PEP_ILLEGAL_VALUE;
  1540. sqlite3_reset(session->update_key_sticky_bit_for_user);
  1541. sqlite3_bind_int(session->update_key_sticky_bit_for_user, 1, sticky);
  1542. sqlite3_bind_text(session->update_key_sticky_bit_for_user, 2, ident->user_id, -1,
  1543. SQLITE_STATIC);
  1544. sqlite3_bind_text(session->update_key_sticky_bit_for_user, 3, fpr, -1,
  1545. SQLITE_STATIC);
  1546. int result = sqlite3_step(session->update_key_sticky_bit_for_user);
  1547. sqlite3_reset(session->update_key_sticky_bit_for_user);
  1548. if (result != SQLITE_DONE) {
  1549. return PEP_CANNOT_SET_TRUST;
  1550. }
  1551. return PEP_STATUS_OK;
  1552. }
  1553. PEP_STATUS get_key_sticky_bit_for_user(PEP_SESSION session,
  1554. const char* user_id,
  1555. const char* fpr,
  1556. bool* is_sticky) {
  1557. PEP_STATUS status = PEP_STATUS_OK;
  1558. if (!session || !is_sticky || EMPTYSTR(user_id) || EMPTYSTR(fpr))
  1559. return PEP_ILLEGAL_VALUE;
  1560. sqlite3_reset(session->is_key_sticky_for_user);
  1561. sqlite3_bind_text(session->is_key_sticky_for_user, 1, user_id, -1,
  1562. SQLITE_STATIC);
  1563. sqlite3_bind_text(session->is_key_sticky_for_user, 2, fpr, -1,
  1564. SQLITE_STATIC);
  1565. int result = sqlite3_step(session->is_key_sticky_for_user);
  1566. switch (result) {
  1567. case SQLITE_ROW: {
  1568. *is_sticky = sqlite3_column_int(session->is_key_sticky_for_user, 0);
  1569. break;
  1570. }
  1571. default:
  1572. status = PEP_KEY_NOT_FOUND;
  1573. }
  1574. return status;
  1575. }
  1576. DYNAMIC_API PEP_STATUS set_comm_partner_key(PEP_SESSION session,
  1577. pEp_identity *identity,
  1578. const char* fpr) {
  1579. if (!session || !identity || EMPTYSTR(fpr))
  1580. return PEP_ILLEGAL_VALUE;
  1581. // update identity upfront - we need the identity to exist in the DB.
  1582. PEP_STATUS status = update_identity(session, identity);
  1583. if (status != PEP_OUT_OF_MEMORY