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.

2270 lines
76 KiB

1 year 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
1 year ago
4 years ago
2 years ago
2 years ago
2 years ago
2 years ago
4 years ago
4 years ago
8 years ago
1 year ago
1 year 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
8 years ago
8 years ago
8 years ago
4 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 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
2 years ago
2 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
1 year 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 = candidate_has_username ? strcmp(candidate->address, candidate->username) == 0 : false;
  660. // This is where the optimisation gets a little weird:
  661. //
  662. // Decide whether to accept and patch the database and stored id from the input,
  663. // Accept and patch the input id from the database, or reject and go to the next
  664. // one in the list
  665. //
  666. // This is unnecessary, but I think the terms need to be descriptive where possible
  667. bool input_addr_only = !input_has_username && !input_has_user_id;
  668. bool candidate_id_best = candidate_has_real_id && !input_has_real_id;
  669. bool input_id_best = input_has_real_id && !candidate_has_real_id;
  670. // bool patch_input_id_conditions = input_has_user_id || names_match || weak_candidate_name; // No longer necessary, as we don't compare usernames
  671. if (input_addr_only || candidate_id_best) {
  672. identity->user_id = strdup(candidate_id);
  673. assert(identity->user_id);
  674. if (!identity->user_id)
  675. goto enomem;
  676. stored_ident = identity_dup(candidate);
  677. break;
  678. }
  679. else if (input_id_best) {
  680. // Replace the TOFU db in the database with the input ID globally
  681. status = replace_userid(session,
  682. candidate_id,
  683. identity->user_id);
  684. if (status != PEP_STATUS_OK) {
  685. free_identity_list(id_list);
  686. free(default_own_id);
  687. return status;
  688. }
  689. // Reflect the change we just made to the DB
  690. free(candidate->user_id);
  691. candidate->user_id = strdup(identity->user_id);
  692. stored_ident = identity_dup(candidate);
  693. break;
  694. } // End else if
  695. // Else, we reject this candidate and try the next one, if there is one.
  696. // Remember, the "user_id"s match case was already taken care of by get_identity
  697. // above.
  698. stored_curr = stored_curr->next;
  699. }
  700. // Ok, we've checked all of the candidates, and if there's a stored identity, there's a duplicate.
  701. // Freeeeeeee...
  702. free_identity_list(id_list);
  703. }
  704. }
  705. // If, by here, there is no user id on the identity, we put one on there.
  706. // We've found any non-TOFU one we're going to find, so if this is empty,
  707. // We don't have a stored ident.
  708. if (EMPTYSTR(identity->user_id)) {
  709. identity->user_id = calloc(1, strlen(identity->address) + 6);
  710. if (!identity->user_id)
  711. goto enomem;
  712. snprintf(identity->user_id, strlen(identity->address) + 6,
  713. "TOFU_%s", identity->address);
  714. // Try one last time to see if there is an ident for us with a TOFU id
  715. //
  716. // We no longer use the username as a qualifying condition.
  717. //
  718. status = get_identity(session,
  719. identity->address,
  720. identity->user_id,
  721. &stored_ident);
  722. }
  723. }
  724. //
  725. // Either update the identity (and possibly DB to reflect stored ident information, or
  726. // create a new identity and store it.
  727. //
  728. if (status == PEP_STATUS_OK && stored_ident) {
  729. // An identity was available.
  730. // Call will patch the username where needed and
  731. // get a valid default key (for ident or user)
  732. status = prepare_updated_identity(session,
  733. identity,
  734. stored_ident, true);
  735. }
  736. else { // No stored ident. We're done.
  737. // If we needed TOFU, we've taken care of the ID above.
  738. if (EMPTYSTR(identity->username)) { // currently, not after messing around
  739. free(identity->username);
  740. identity->username = strdup(identity->address);
  741. if (!identity->username)
  742. goto enomem;
  743. }
  744. free(identity->fpr);
  745. identity->fpr = NULL;
  746. identity->comm_type = PEP_ct_unknown;
  747. adjust_pEp_trust_status(session, identity);
  748. status = set_identity(session, identity);
  749. // This is ONLY for the return value - VB confirms we should tell the user we didn't find a key
  750. if (identity->comm_type == PEP_ct_unknown)
  751. identity->comm_type = PEP_ct_key_not_found;
  752. }
  753. // VB says, and I quote, "that is not implemented and no one is using it right now"
  754. // about this bit. So, um, you're forewarned.
  755. if (identity->comm_type != PEP_ct_compromised &&
  756. identity->comm_type < PEP_ct_strong_but_unconfirmed)
  757. if (session->examine_identity)
  758. session->examine_identity(identity, session->examine_management);
  759. goto pEp_free;
  760. enomem:
  761. status = PEP_OUT_OF_MEMORY;
  762. pEp_free:
  763. free(default_own_id);
  764. free_identity(stored_ident);
  765. return status;
  766. }
  767. /**
  768. * @internal
  769. *
  770. * <!-- elect_ownkey() -->
  771. *
  772. * @brief TODO
  773. *
  774. * @param[in] session session handle
  775. * @param[in] *identity pEp_identity
  776. *
  777. * @retval PEP_STATUS_OK
  778. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  779. * @retval PEP_OUT_OF_MEMORY out of memory
  780. * @retval any other value on error
  781. */
  782. PEP_STATUS elect_ownkey(
  783. PEP_SESSION session, pEp_identity * identity
  784. )
  785. {
  786. if (!(session && identity))
  787. return PEP_ILLEGAL_VALUE;
  788. PEP_STATUS status;
  789. stringlist_t *keylist = NULL;
  790. free(identity->fpr);
  791. identity->fpr = NULL;
  792. status = find_private_keys(session, identity->address, &keylist);
  793. assert(status != PEP_OUT_OF_MEMORY);
  794. if (status == PEP_OUT_OF_MEMORY)
  795. return PEP_OUT_OF_MEMORY;
  796. if (keylist != NULL && keylist->value != NULL)
  797. {
  798. char *_fpr = NULL;
  799. identity->comm_type = PEP_ct_unknown;
  800. stringlist_t *_keylist;
  801. for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
  802. bool is_own = false;
  803. status = own_key_is_listed(session, _keylist->value, &is_own);
  804. assert(status == PEP_STATUS_OK);
  805. if (status != PEP_STATUS_OK) {
  806. free_stringlist(keylist);
  807. return status;
  808. }
  809. if (is_own)
  810. {
  811. PEP_comm_type _comm_type_key;
  812. status = get_key_rating(session, _keylist->value, &_comm_type_key);
  813. assert(status != PEP_OUT_OF_MEMORY);
  814. if (status == PEP_OUT_OF_MEMORY) {
  815. free_stringlist(keylist);
  816. return PEP_OUT_OF_MEMORY;
  817. }
  818. if (_comm_type_key != PEP_ct_compromised &&
  819. _comm_type_key != PEP_ct_unknown)
  820. {
  821. if (identity->comm_type == PEP_ct_unknown ||
  822. _comm_type_key > identity->comm_type)
  823. {
  824. identity->comm_type = _comm_type_key;
  825. _fpr = _keylist->value;
  826. }
  827. }
  828. }
  829. }
  830. if (_fpr)
  831. {
  832. identity->fpr = strdup(_fpr);
  833. assert(identity->fpr);
  834. if (identity->fpr == NULL)
  835. {
  836. free_stringlist(keylist);
  837. return PEP_OUT_OF_MEMORY;
  838. }
  839. }
  840. free_stringlist(keylist);
  841. }
  842. return PEP_STATUS_OK;
  843. }
  844. /**
  845. * @internal
  846. *
  847. * <!-- _has_usable_priv_key() -->
  848. *
  849. * @brief TODO
  850. *
  851. * @param[in] session session handle
  852. * @param[in] *fpr char
  853. * @param[in] *is_usable bool
  854. *
  855. * @retval PEP_STATUS_OK
  856. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  857. * @retval any other value on error
  858. */
  859. PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
  860. bool* is_usable) {
  861. bool has_private = false;
  862. PEP_STATUS status = contains_priv_key(session, fpr, &has_private);
  863. *is_usable = has_private;
  864. return status;
  865. }
  866. PEP_STATUS _myself(PEP_SESSION session,
  867. pEp_identity * identity,
  868. bool do_keygen,
  869. bool do_renew,
  870. bool ignore_flags,
  871. bool read_only)
  872. {
  873. PEP_STATUS status;
  874. assert(session);
  875. assert(identity);
  876. assert(!EMPTYSTR(identity->address));
  877. if (!session || !identity || EMPTYSTR(identity->address))
  878. return PEP_ILLEGAL_VALUE;
  879. // this leads to crashes otherwise
  880. if (!(identity->user_id && identity->user_id[0])) {
  881. free(identity->user_id);
  882. identity->user_id = strdup(PEP_OWN_USERID);
  883. assert(identity->user_id);
  884. if (!identity->user_id)
  885. return PEP_OUT_OF_MEMORY;
  886. }
  887. // Cache the input username, if there is one and it's not read_only
  888. char* cached_input_username = NULL;
  889. if (!read_only && identity->username) {
  890. cached_input_username = strdup(identity->username);
  891. if (!cached_input_username)
  892. return PEP_OUT_OF_MEMORY;
  893. }
  894. pEp_identity *stored_identity = NULL;
  895. char* revoked_fpr = NULL;
  896. bool valid_key_found = false;
  897. char* default_own_id = NULL;
  898. status = get_default_own_userid(session, &default_own_id);
  899. // Deal with non-default user_ids.
  900. // FIXME: if non-default and read-only, reject totally?
  901. if (default_own_id && strcmp(default_own_id, identity->user_id) != 0) {
  902. if (read_only) {
  903. free(identity->user_id);
  904. identity->user_id = strdup(default_own_id);
  905. assert(identity->user_id);
  906. if (!identity->user_id)
  907. return PEP_OUT_OF_MEMORY;
  908. }
  909. else {
  910. status = set_userid_alias(session, default_own_id, identity->user_id);
  911. // Do we want this to be fatal? For now, we'll do it...
  912. if (status != PEP_STATUS_OK)
  913. goto pEp_free;
  914. free(identity->user_id);
  915. identity->user_id = strdup(default_own_id);
  916. assert(identity->user_id);
  917. if (identity->user_id == NULL) {
  918. status = PEP_OUT_OF_MEMORY;
  919. goto pEp_free;
  920. }
  921. }
  922. }
  923. // NOTE: IF WE DON'T YET HAVE AN OWN_ID, WE IGNORE REFERENCES TO THIS ADDRESS IN THE
  924. // DB (WHICH MAY HAVE BEEN SET BEFORE MYSELF WAS CALLED BY RECEIVING AN EMAIL FROM
  925. // THIS ADDRESS), AS IT IS NOT AN OWN_IDENTITY AND HAS NO INFORMATION WE NEED OR WHAT TO
  926. // SET FOR MYSELF
  927. // Ok, so now, set up the own_identity:
  928. identity->comm_type = PEP_ct_pEp;
  929. identity->me = true;
  930. if(ignore_flags)
  931. identity->flags = 0;
  932. // Let's see if we have an identity record in the DB for
  933. // this user_id + address
  934. // DEBUG_LOG("myself", "debug", identity->address);
  935. // This will grab the actual flags from the db
  936. status = get_identity(session,
  937. identity->address,
  938. identity->user_id,
  939. &stored_identity);
  940. assert(status != PEP_OUT_OF_MEMORY);
  941. if (status == PEP_OUT_OF_MEMORY) {
  942. status = PEP_OUT_OF_MEMORY;
  943. goto pEp_free;
  944. }
  945. // Set usernames - priority is input username > stored name > address
  946. // If there's an input username, we always patch the username with that
  947. // input.
  948. // N.B. there was an || read_only here, but why? read_only ONLY means
  949. // we don't write to the DB! So... removed. But how this managed to work
  950. // before I don't know.
  951. if (EMPTYSTR(identity->username)) {
  952. bool stored_uname = (stored_identity && !EMPTYSTR(stored_identity->username));
  953. char* uname = (stored_uname ? stored_identity->username : identity->address);
  954. if (uname) {
  955. free(identity->username);
  956. identity->username = strdup(uname);
  957. assert(identity->username);
  958. if (identity->username == NULL) {
  959. status = PEP_OUT_OF_MEMORY;
  960. goto pEp_free;
  961. }
  962. }
  963. }
  964. // ignore input fpr
  965. if (identity->fpr) {
  966. free(identity->fpr);
  967. identity->fpr = NULL;
  968. }
  969. // check stored identity
  970. if (stored_identity) {
  971. if (!EMPTYSTR(stored_identity->fpr)) {
  972. // Fall back / retrieve
  973. status = validate_fpr(session, stored_identity, true, do_renew);
  974. switch (status) {
  975. // Only possible if we called this with do_renew = true
  976. case PEP_OUT_OF_MEMORY:
  977. case PEP_PASSPHRASE_REQUIRED:
  978. case PEP_WRONG_PASSPHRASE:
  979. goto pEp_free;
  980. case PEP_STATUS_OK:
  981. if (stored_identity->comm_type >= PEP_ct_strong_but_unconfirmed) {
  982. identity->fpr = strdup(stored_identity->fpr);
  983. assert(identity->fpr);
  984. if (!identity->fpr) {
  985. status = PEP_OUT_OF_MEMORY;
  986. goto pEp_free;
  987. }
  988. valid_key_found = true;
  989. }
  990. else {
  991. bool revoked = false;
  992. status = key_revoked(session, stored_identity->fpr, &revoked);
  993. if (status)
  994. goto pEp_free;
  995. if (revoked) {
  996. revoked_fpr = strdup(stored_identity->fpr);
  997. assert(revoked_fpr);
  998. if (!revoked_fpr) {
  999. status = PEP_OUT_OF_MEMORY;
  1000. goto pEp_free;
  1001. }
  1002. }
  1003. }
  1004. break;
  1005. default:
  1006. break;
  1007. }
  1008. }
  1009. // reconcile language, flags
  1010. transfer_ident_lang_and_flags(identity, stored_identity);
  1011. }
  1012. // Nothing left to do but generate a key
  1013. if (!valid_key_found) {
  1014. if (!do_keygen || read_only)
  1015. status = PEP_GET_KEY_FAILED;
  1016. else {
  1017. // / DEBUG_LOG("Generating key pair", "debug", identity->address);
  1018. free(identity->fpr);
  1019. identity->fpr = NULL;
  1020. status = generate_keypair(session, identity);
  1021. assert(status != PEP_OUT_OF_MEMORY);
  1022. if (status == PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED)
  1023. goto pEp_free;
  1024. if (status != PEP_STATUS_OK) {
  1025. char buf[11];
  1026. snprintf(buf, 11, "%d", status); // uh, this is kludgey. FIXME
  1027. // DEBUG_LOG("Generating key pair failed", "debug", buf);
  1028. }
  1029. else {
  1030. valid_key_found = true;
  1031. if (revoked_fpr) {
  1032. status = set_revoked(session, revoked_fpr,
  1033. stored_identity->fpr, time(NULL));
  1034. assert(status == PEP_STATUS_OK);
  1035. }
  1036. }
  1037. }
  1038. }
  1039. if (valid_key_found) {
  1040. identity->comm_type = PEP_ct_pEp;
  1041. status = PEP_STATUS_OK;
  1042. }
  1043. else {
  1044. free(identity->fpr);
  1045. identity->fpr = NULL;
  1046. identity->comm_type = PEP_ct_unknown;
  1047. }
  1048. unsigned int major_ver = 0;
  1049. unsigned int minor_ver = 0;
  1050. pEp_version_major_minor(PEP_VERSION, &major_ver, &minor_ver);
  1051. identity->major_ver = major_ver;
  1052. identity->minor_ver = minor_ver;
  1053. // We want to set an identity in the DB even if a key isn't found, but we have to preserve the status if
  1054. // it's NOT ok
  1055. if (!read_only) {
  1056. // set identity will not automatically set identity.username in the database, only
  1057. // the person.username (user default). So we set it here, but will then force-set the name again if we
  1058. // have to.
  1059. PEP_STATUS set_id_status = set_identity(session, identity);
  1060. if (set_id_status == PEP_STATUS_OK)
  1061. set_id_status = set_as_pEp_user(session, identity);
  1062. if (set_id_status == PEP_STATUS_OK && cached_input_username) {
  1063. // Force-set input username
  1064. set_id_status = force_set_identity_username(session, identity, cached_input_username);
  1065. free(identity->username);
  1066. identity->username = cached_input_username;
  1067. cached_input_username = NULL;
  1068. }
  1069. status = (status == PEP_STATUS_OK ? set_id_status : status);
  1070. }
  1071. pEp_free:
  1072. free(default_own_id);
  1073. free(revoked_fpr);
  1074. free_identity(stored_identity);
  1075. free(cached_input_username);
  1076. return status;
  1077. }
  1078. DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
  1079. {
  1080. return _myself(session, identity, true, true, false, false);
  1081. }
  1082. DYNAMIC_API PEP_STATUS register_examine_function(
  1083. PEP_SESSION session,
  1084. examine_identity_t examine_identity,
  1085. void *management
  1086. )
  1087. {
  1088. assert(session);
  1089. if (!session)
  1090. return PEP_ILLEGAL_VALUE;
  1091. session->examine_management = management;
  1092. session->examine_identity = examine_identity;
  1093. return PEP_STATUS_OK;
  1094. }
  1095. DYNAMIC_API PEP_STATUS do_keymanagement(
  1096. retrieve_next_identity_t retrieve_next_identity,
  1097. void *management
  1098. )
  1099. {
  1100. PEP_SESSION session;
  1101. pEp_identity *identity;
  1102. // FIXME_NOW: ensure_decrypt callback???
  1103. PEP_STATUS status = init(&session, NULL, NULL, NULL);
  1104. assert(!status);
  1105. if (status)
  1106. return status;
  1107. assert(session && retrieve_next_identity);
  1108. if (!(session && retrieve_next_identity))
  1109. return PEP_ILLEGAL_VALUE;
  1110. log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
  1111. while ((identity = retrieve_next_identity(management)))
  1112. {
  1113. assert(identity->address);
  1114. if(identity->address)
  1115. {
  1116. DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
  1117. if (identity->me) {
  1118. status = myself(session, identity);
  1119. } else {
  1120. status = recv_key(session, identity->address);
  1121. }
  1122. assert(status != PEP_OUT_OF_MEMORY);
  1123. if(status == PEP_OUT_OF_MEMORY)
  1124. return PEP_OUT_OF_MEMORY;
  1125. }
  1126. free_identity(identity);
  1127. }
  1128. log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
  1129. release(session);
  1130. return PEP_STATUS_OK;
  1131. }
  1132. DYNAMIC_API PEP_STATUS key_mistrusted(
  1133. PEP_SESSION session,
  1134. pEp_identity *ident
  1135. )
  1136. {
  1137. PEP_STATUS status = PEP_STATUS_OK;
  1138. assert(session);
  1139. assert(ident);
  1140. assert(!EMPTYSTR(ident->fpr));
  1141. if (!(session && ident && ident->fpr))
  1142. return PEP_ILLEGAL_VALUE;
  1143. bool has_private = false;
  1144. status = contains_priv_key(session, ident->fpr, &has_private);
  1145. if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
  1146. return status;
  1147. // See if key is revoked already
  1148. if (has_private) {
  1149. bool revoked = false;
  1150. status = key_revoked(session, ident->fpr, &revoked);
  1151. if (!revoked)
  1152. revoke_key(session, ident->fpr, NULL);
  1153. }
  1154. else {
  1155. if (ident->fpr) {
  1156. // Make sure there was a default in the DB for this identity;
  1157. // if not, set one, even though we're going to mistrust this. Otherwise,
  1158. // cannot reset.
  1159. pEp_identity* stored_ident = NULL;
  1160. get_identity(session, ident->address, ident->user_id, &stored_ident);
  1161. bool set_in_db = true;
  1162. if (!stored_ident)
  1163. stored_ident = identity_dup(ident);
  1164. else if (!stored_ident->fpr)
  1165. stored_ident->fpr = strdup(ident->fpr);
  1166. else
  1167. set_in_db = false;
  1168. if (set_in_db)
  1169. status = set_identity(session, stored_ident);
  1170. free_identity(stored_ident);
  1171. if (status != PEP_STATUS_OK)
  1172. return status;
  1173. }
  1174. }
  1175. // double-check to be sure key is even in the DB
  1176. if (ident->fpr)
  1177. status = set_pgp_keypair(session, ident->fpr);
  1178. // We set this temporarily but will grab it back from the cache afterwards
  1179. ident->comm_type = PEP_ct_mistrusted;
  1180. status = set_trust(session, ident);
  1181. if (status == PEP_STATUS_OK)
  1182. // cascade that mistrust for anyone using this key
  1183. status = mark_as_compromised(session, ident->fpr);
  1184. if (status == PEP_STATUS_OK)
  1185. status = add_mistrusted_key(session, ident->fpr);
  1186. return status;
  1187. }
  1188. DYNAMIC_API PEP_STATUS key_reset_trust(
  1189. PEP_SESSION session,
  1190. pEp_identity *ident
  1191. )
  1192. {
  1193. PEP_STATUS status = PEP_STATUS_OK;
  1194. assert(session);
  1195. assert(ident);
  1196. assert(!EMPTYSTR(ident->fpr));
  1197. assert(!EMPTYSTR(ident->address));
  1198. assert(!EMPTYSTR(ident->user_id));
  1199. if (!(session && ident && ident->fpr && ident->fpr[0] != '\0' && ident->address &&
  1200. ident->user_id))
  1201. return PEP_ILLEGAL_VALUE;
  1202. // we do not change the input struct at ALL.
  1203. pEp_identity* input_copy = identity_dup(ident);
  1204. pEp_identity* tmp_ident = NULL;
  1205. status = get_trust(session, input_copy);
  1206. if (status != PEP_STATUS_OK)
  1207. goto pEp_free;
  1208. PEP_comm_type new_trust = PEP_ct_unknown;
  1209. status = get_key_rating(session, ident->fpr, &new_trust);
  1210. if (status != PEP_STATUS_OK)
  1211. goto pEp_free;
  1212. bool pEp_user = false;
  1213. status = is_pEp_user(session, ident, &pEp_user);
  1214. if (pEp_user && new_trust >= PEP_ct_unconfirmed_encryption)
  1215. input_copy->comm_type = PEP_ct_pEp_unconfirmed;
  1216. else
  1217. input_copy->comm_type = new_trust;
  1218. status = set_trust(session, input_copy);
  1219. if (status != PEP_STATUS_OK)
  1220. goto pEp_free;
  1221. bool mistrusted_key = false;
  1222. status = is_mistrusted_key(session, ident->fpr, &mistrusted_key);
  1223. if (status != PEP_STATUS_OK)
  1224. goto pEp_free;
  1225. if (mistrusted_key)
  1226. status = delete_mistrusted_key(session, ident->fpr);
  1227. if (status != PEP_STATUS_OK)
  1228. goto pEp_free;
  1229. tmp_ident = new_identity(ident->address, NULL, ident->user_id, NULL);
  1230. if (!tmp_ident)
  1231. return PEP_OUT_OF_MEMORY;
  1232. if (is_me(session, tmp_ident))
  1233. status = myself(session, tmp_ident);
  1234. else
  1235. status = update_identity(session, tmp_ident);
  1236. if (status != PEP_STATUS_OK)
  1237. goto pEp_free;
  1238. // remove as default if necessary
  1239. if (!EMPTYSTR(tmp_ident->fpr) && strcmp(tmp_ident->fpr, ident->fpr) == 0) {
  1240. free(tmp_ident->fpr);
  1241. tmp_ident->fpr = NULL;
  1242. tmp_ident->comm_type = PEP_ct_unknown;
  1243. status = set_identity(session, tmp_ident);
  1244. if (status != PEP_STATUS_OK)
  1245. goto pEp_free;
  1246. }
  1247. char* user_default = NULL;
  1248. get_main_user_fpr(session, tmp_ident->user_id, &user_default);
  1249. if (!EMPTYSTR(user_default)) {
  1250. if (strcmp(user_default, ident->fpr) == 0)
  1251. status = refresh_userid_default_key(session, ident->user_id);
  1252. if (status != PEP_STATUS_OK)
  1253. goto pEp_free;
  1254. }
  1255. pEp_free:
  1256. free_identity(tmp_ident);
  1257. free_identity(input_copy);
  1258. return status;
  1259. }
  1260. // Technically speaking, this should not EVER
  1261. // return PASSPHRASE errors, because
  1262. // this is never for an own identity (enforced), and thus
  1263. // validate_fpr will not call renew_key.
  1264. // If it ever does, the status gets propagated, but
  1265. // it is distinctly not OK.
  1266. DYNAMIC_API PEP_STATUS trust_personal_key(
  1267. PEP_SESSION session,
  1268. pEp_identity *ident
  1269. )
  1270. {
  1271. PEP_STATUS status = PEP_STATUS_OK;
  1272. assert(session);
  1273. assert(ident);
  1274. assert(!EMPTYSTR(ident->address));
  1275. assert(!EMPTYSTR(ident->user_id));
  1276. assert(!EMPTYSTR(ident->fpr));
  1277. if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  1278. EMPTYSTR(ident->fpr))
  1279. return PEP_ILLEGAL_VALUE;
  1280. if (is_me(session, ident))
  1281. return PEP_ILLEGAL_VALUE;
  1282. char* ident_default_fpr = NULL;
  1283. // Before we do anything, be sure the input fpr is even eligible to be trusted
  1284. PEP_comm_type input_default_ct = PEP_ct_unknown;
  1285. status = get_key_rating(session, ident->fpr, &input_default_ct);
  1286. if (input_default_ct < PEP_ct_strong_but_unconfirmed)
  1287. return PEP_KEY_UNSUITABLE;
  1288. status = set_pgp_keypair(session, ident->fpr);
  1289. if (status != PEP_STATUS_OK)
  1290. return status;
  1291. pEp_identity* ident_copy = identity_dup(ident);
  1292. char* cached_fpr = NULL;
  1293. // for setting up a temp trusted identity for the input fpr
  1294. pEp_identity* tmp_id = NULL;
  1295. // For later, in case we need to check the user default key
  1296. pEp_identity* tmp_user_ident = NULL;
  1297. // Save the input fpr, which we already tested as non-NULL
  1298. cached_fpr = strdup(ident->fpr);
  1299. // Set up a temp trusted identity for the input fpr without a comm type;
  1300. tmp_id = new_identity(ident->address, ident->fpr, ident->user_id, NULL);
  1301. status = validate_fpr(session, tmp_id, true, false);
  1302. if (status == PEP_STATUS_OK) {
  1303. // Validate fpr gets trust DB or, when that fails, key comm type. we checked
  1304. // above that the key was ok. (not revoked or expired), but we want the max.
  1305. tmp_id->comm_type = _MAX(tmp_id->comm_type, input_default_ct) | PEP_ct_confirmed;
  1306. // Get the default identity without setting the fpr
  1307. status = update_identity(session, ident_copy);
  1308. ident_default_fpr = (EMPTYSTR(ident_copy->fpr) ? NULL : strdup(ident_copy->fpr));
  1309. if (status == PEP_STATUS_OK) {
  1310. bool trusted_default = false;
  1311. // If there's no default, or the default is different from the input...
  1312. if (EMPTYSTR(ident_default_fpr) || strcmp(cached_fpr, ident_default_fpr) != 0) {
  1313. // If the default fpr (if there is one) is trusted and key is strong enough,
  1314. // don't replace, we just set the trusted bit on this key for this user_id...
  1315. // (If there's no default fpr, this won't be true anyway.)
  1316. if ((ident_copy->comm_type >= PEP_ct_strong_but_unconfirmed &&
  1317. (ident_copy->comm_type & PEP_ct_confirmed))) {
  1318. trusted_default = true;
  1319. status = set_trust(session, tmp_id);
  1320. input_default_ct = tmp_id->comm_type;
  1321. }
  1322. else {
  1323. free(ident_copy->fpr);
  1324. ident_copy->fpr = strdup(cached_fpr);
  1325. ident_copy->comm_type = tmp_id->comm_type;
  1326. status = set_identity(session, ident_copy); // replace identity default
  1327. if (status == PEP_STATUS_OK) {
  1328. if ((ident_copy->comm_type | PEP_ct_confirmed) == PEP_ct_pEp)
  1329. status = set_as_pEp_user(session, ident_copy);
  1330. }
  1331. }
  1332. }
  1333. else { // we're setting this on the default fpr
  1334. ident->comm_type = tmp_id->comm_type;
  1335. status = set_identity(session, ident);
  1336. trusted_default = true;
  1337. }
  1338. if (status == PEP_STATUS_OK && !trusted_default) {
  1339. // Ok, there wasn't a trusted default, so we replaced. Thus, we also
  1340. // make sure there's a trusted default on the user_id. If there
  1341. // is not, we make this the default.
  1342. char* user_default = NULL;
  1343. status = get_main_user_fpr(session, ident->user_id, &user_default);
  1344. if (status == PEP_STATUS_OK && user_default) {
  1345. tmp_user_ident = new_identity(ident->address,
  1346. user_default,
  1347. ident->user_id,
  1348. NULL);
  1349. if (!tmp_user_ident)
  1350. status = PEP_OUT_OF_MEMORY;
  1351. else {
  1352. status = validate_fpr(session, tmp_user_ident, true, false);
  1353. if (status != PEP_STATUS_OK ||
  1354. tmp_user_ident->comm_type < PEP_ct_strong_but_unconfirmed ||
  1355. !(tmp_user_ident->comm_type & PEP_ct_confirmed))
  1356. {
  1357. char* trusted_fpr = (trusted_default ? ident_default_fpr : cached_fpr);
  1358. status = replace_main_user_fpr(session, ident->user_id, trusted_fpr);
  1359. }
  1360. }
  1361. }
  1362. }
  1363. }
  1364. }
  1365. free(ident_default_fpr);
  1366. free(cached_fpr);
  1367. free_identity(tmp_id);
  1368. free_identity(ident_copy);
  1369. free_identity(tmp_user_ident);
  1370. return status;
  1371. }
  1372. DYNAMIC_API PEP_STATUS trust_own_key(
  1373. PEP_SESSION session,
  1374. pEp_identity* ident
  1375. )
  1376. {
  1377. assert(session);
  1378. assert(ident);
  1379. assert(!EMPTYSTR(ident->address));
  1380. assert(!EMPTYSTR(ident->user_id));
  1381. assert(!EMPTYSTR(ident->fpr));
  1382. if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  1383. EMPTYSTR(ident->fpr))
  1384. return PEP_ILLEGAL_VALUE;
  1385. if (!is_me(session, ident))
  1386. return PEP_ILLEGAL_VALUE;
  1387. // don't require a private key
  1388. PEP_STATUS status = validate_fpr(session, ident, false, true);
  1389. if (status !