p≡p engine fork for my own dirty testing of stuff
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.

2416 lines
81 KiB

9 months ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
9 months ago
9 months ago
8 years ago
3 years ago
3 years ago
8 years ago
7 years ago
5 years ago
5 years ago
8 years ago
3 years ago
3 years ago
3 years ago
3 years ago
9 months ago
3 years ago
1 year ago
1 year ago
1 year ago
1 year ago
3 years ago
3 years ago
8 years ago
9 months ago
9 months ago
8 years ago
8 years ago
7 years ago
3 years ago
3 years ago
8 years ago
8 years ago
3 years ago
3 years ago
8 years ago
8 years ago
3 years ago
7 years ago
8 years ago
8 years ago
8 years ago
3 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 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
9 months 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
9 months 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
9 months ago
9 months 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. #include "blacklist.h"
  18. static bool key_matches_address(PEP_SESSION session, const char* address,
  19. const char* fpr) {
  20. if (!session || !address || !fpr)
  21. return false;
  22. bool retval = false;
  23. stringlist_t *keylist = NULL;
  24. PEP_STATUS status = find_keys(session, address, &keylist);
  25. if (status == PEP_STATUS_OK && keylist) {
  26. stringlist_t* curr = keylist;
  27. while (curr) {
  28. if (curr->value) {
  29. if (strcasecmp(curr->value, fpr)) {
  30. retval = true;
  31. break;
  32. }
  33. }
  34. curr = curr->next;
  35. }
  36. }
  37. free_stringlist(keylist);
  38. return retval;
  39. }
  40. // Does not return PASSPHRASE errors
  41. /**
  42. * @internal
  43. *
  44. * <!-- elect_pubkey() -->
  45. *
  46. * @brief TODO
  47. *
  48. * @param[in] session session handle
  49. * @param[in] *identity pEp_identity
  50. * @param[in] check_blacklist bool
  51. *
  52. * @retval PEP_STATUS_OK
  53. * @retval PEP_OUT_OF_MEMORY out of memory
  54. */
  55. PEP_STATUS elect_pubkey(
  56. PEP_SESSION session, pEp_identity * identity, bool check_blacklist
  57. )
  58. {
  59. PEP_STATUS status;
  60. stringlist_t *keylist = NULL;
  61. char *_fpr = "";
  62. identity->comm_type = PEP_ct_unknown;
  63. status = find_keys(session, identity->address, &keylist);
  64. assert(status != PEP_OUT_OF_MEMORY);
  65. if (status == PEP_OUT_OF_MEMORY)
  66. return PEP_OUT_OF_MEMORY;
  67. if (!keylist || !keylist->value)
  68. identity->comm_type = PEP_ct_key_not_found;
  69. else {
  70. stringlist_t *_keylist;
  71. for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
  72. PEP_comm_type _comm_type_key;
  73. status = get_key_rating(session, _keylist->value, &_comm_type_key);
  74. if (status == PEP_OUT_OF_MEMORY) {
  75. free_stringlist(keylist);
  76. return PEP_OUT_OF_MEMORY;
  77. }
  78. if (_comm_type_key != PEP_ct_compromised &&
  79. _comm_type_key != PEP_ct_unknown)
  80. {
  81. if (identity->comm_type == PEP_ct_unknown ||
  82. _comm_type_key > identity->comm_type)
  83. {
  84. bool blacklisted = false;
  85. bool mistrusted = false;
  86. status = is_mistrusted_key(session, _keylist->value, &mistrusted);
  87. if (status == PEP_STATUS_OK && check_blacklist)
  88. status = blacklist_is_listed(session, _keylist->value, &blacklisted);
  89. if (status == PEP_STATUS_OK && !mistrusted && !blacklisted) {
  90. identity->comm_type = _comm_type_key;
  91. _fpr = _keylist->value;
  92. }
  93. }
  94. }
  95. }
  96. }
  97. free(identity->fpr);
  98. if (!_fpr || _fpr[0] == '\0')
  99. identity->fpr = NULL;
  100. else {
  101. identity->fpr = strdup(_fpr);
  102. if (identity->fpr == NULL) {
  103. free_stringlist(keylist);
  104. return PEP_OUT_OF_MEMORY;
  105. }
  106. }
  107. free_stringlist(keylist);
  108. return PEP_STATUS_OK;
  109. }
  110. // own_must_contain_private is usually true when calling;
  111. // we only set it to false when we have the idea of
  112. // possibly having an own pubkey that we need to check on its own
  113. // N.B. Checked for PASSPHRASE errors - will now return them always
  114. // False value of "renew_private" prevents their possibility, though.
  115. /**
  116. * @internal
  117. *
  118. * <!-- validate_fpr() -->
  119. *
  120. * @brief TODO
  121. *
  122. * @param[in] session session handle
  123. * @param[in] *ident pEp_identity
  124. * @param[in] check_blacklist bool
  125. * @param[in] own_must_contain_private bool
  126. * @param[in] renew_private bool
  127. *
  128. * @retval PEP_STATUS_OK
  129. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  130. * @retval PEP_OUT_OF_MEMORY out of memory
  131. * @retval PEP_KEY_UNSUITABLE
  132. * @retval PEP_PASSPHRASE_REQUIRED
  133. * @retval PEP_WRONG_PASSPHRASE
  134. * @retval any other value on error
  135. *
  136. */
  137. PEP_STATUS validate_fpr(PEP_SESSION session,
  138. pEp_identity* ident,
  139. bool check_blacklist,
  140. bool own_must_contain_private,
  141. bool renew_private) {
  142. PEP_STATUS status = PEP_STATUS_OK;
  143. if (!session || !ident || !ident->fpr || !ident->fpr[0])
  144. return PEP_ILLEGAL_VALUE;
  145. char* fpr = ident->fpr;
  146. bool has_private = false;
  147. status = contains_priv_key(session, fpr, &has_private);
  148. // N.B. Will not contain PEP_PASSPHRASE related returns here
  149. if (ident->me && own_must_contain_private) {
  150. if (status != PEP_STATUS_OK || !has_private)
  151. return PEP_KEY_UNSUITABLE;
  152. }
  153. else if (status != PEP_STATUS_OK && has_private) // should never happen
  154. has_private = false;
  155. ident->comm_type = PEP_ct_unknown;
  156. status = get_trust(session, ident);
  157. if (status != PEP_STATUS_OK)
  158. ident->comm_type = PEP_ct_unknown;
  159. PEP_comm_type ct = ident->comm_type;
  160. if (ct == PEP_ct_unknown) {
  161. // If status is bad, it's ok, we get the rating
  162. // we should use then (PEP_ct_unknown).
  163. // Only one we really care about here is PEP_OUT_OF_MEMORY
  164. status = get_key_rating(session, fpr, &ct);
  165. if (status == PEP_OUT_OF_MEMORY)
  166. return PEP_OUT_OF_MEMORY;
  167. ident->comm_type = ct;
  168. }
  169. else if (ct == PEP_ct_key_expired || ct == PEP_ct_key_expired_but_confirmed) {
  170. PEP_comm_type ct_expire_check = PEP_ct_unknown;
  171. status = get_key_rating(session, fpr, &ct_expire_check);
  172. if (status == PEP_OUT_OF_MEMORY)
  173. return PEP_OUT_OF_MEMORY;
  174. if (ct_expire_check >= PEP_ct_strong_but_unconfirmed) {
  175. ident->comm_type = ct_expire_check;
  176. if (ct == PEP_ct_key_expired_but_confirmed)
  177. ident->comm_type |= PEP_ct_confirmed;
  178. ct = ident->comm_type;
  179. // We need to fix this trust in the DB.
  180. status = set_trust(session, ident);
  181. }
  182. }
  183. bool pEp_user = false;
  184. status = is_pEp_user(session, ident, &pEp_user);
  185. if (status == PEP_OUT_OF_MEMORY)
  186. return PEP_OUT_OF_MEMORY;
  187. if (pEp_user) {
  188. switch (ct) {
  189. case PEP_ct_OpenPGP:
  190. case PEP_ct_OpenPGP_unconfirmed:
  191. ct += 0x47; // difference between PEP and OpenPGP values;
  192. ident->comm_type = ct;
  193. break;
  194. default:
  195. break;
  196. }
  197. }
  198. bool revoked, expired;
  199. bool blacklisted = false;
  200. // Should not need to decrypt key material
  201. status = key_revoked(session, fpr, &revoked);
  202. if (status != PEP_STATUS_OK) {
  203. return status;
  204. }
  205. if (!revoked) {
  206. time_t exp_time = (ident->me ?
  207. time(NULL) + (7*24*3600) : time(NULL));
  208. // Should not need to decrypt key material
  209. status = key_expired(session, fpr,
  210. exp_time,
  211. &expired);
  212. assert(status == PEP_STATUS_OK);
  213. if (status != PEP_STATUS_OK)
  214. return status;
  215. if (check_blacklist && IS_PGP_CT(ct) &&
  216. !ident->me) {
  217. status = blacklist_is_listed(session,
  218. fpr,
  219. &blacklisted);
  220. if (status != PEP_STATUS_OK)
  221. return status;
  222. }
  223. }
  224. // Renew key if it's expired, our own, has a private part,
  225. // isn't too weak, and we didn't say "DON'T DO THIS"
  226. if (renew_private && ident->me && has_private &&
  227. (ct >= PEP_ct_strong_but_unconfirmed) &&
  228. !revoked && expired) {
  229. // extend key
  230. timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
  231. status = renew_key(session, fpr, ts);
  232. free_timestamp(ts);
  233. if (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE)
  234. return status;
  235. if (status == PEP_STATUS_OK) {
  236. // if key is valid (second check because pEp key might be extended above)
  237. // Return fpr
  238. status = key_expired(session, fpr, time(NULL), &expired);
  239. if (status != PEP_STATUS_OK)
  240. return status;
  241. if (expired) {
  242. if (ident->comm_type & PEP_ct_confirmed || (ident->comm_type == PEP_ct_key_expired_but_confirmed))
  243. ident->comm_type = PEP_ct_key_expired_but_confirmed;
  244. else
  245. ident->comm_type = PEP_ct_key_expired;
  246. return status;
  247. }
  248. // communicate key(?)
  249. }
  250. }
  251. if (revoked)
  252. ct = PEP_ct_key_revoked;
  253. else if (expired) {
  254. if (ident->comm_type & PEP_ct_confirmed || (ident->comm_type == PEP_ct_key_expired_but_confirmed))
  255. ct = PEP_ct_key_expired_but_confirmed;
  256. else
  257. ct = PEP_ct_key_expired;
  258. }
  259. else if (blacklisted) { // never true for .me
  260. ident->comm_type = ct = PEP_ct_key_not_found;
  261. free(ident->fpr);
  262. ident->fpr = strdup("");
  263. status = PEP_KEY_BLACKLISTED;
  264. }
  265. switch (ct) {
  266. case PEP_ct_key_revoked:
  267. case PEP_ct_key_b0rken:
  268. // delete key from being default key for all users/identities
  269. status = remove_fpr_as_default(session, fpr);
  270. // fallthrough intentional!
  271. case PEP_ct_key_expired:
  272. case PEP_ct_key_expired_but_confirmed:
  273. // Note: we no longer remove expired keys as defaults; pEp users
  274. // will either send us an updated key or a key reset, and OpenPGP
  275. // users can either do the same or request a manual key reset.
  276. // We don't want to upset the automated updating of expired keys.
  277. status = update_trust_for_fpr(session,
  278. fpr,
  279. ct);
  280. case PEP_ct_mistrusted:
  281. free(ident->fpr);
  282. ident->fpr = NULL;
  283. ident->comm_type = ct;
  284. status = PEP_KEY_UNSUITABLE;
  285. default:
  286. break;
  287. }
  288. return status;
  289. }
  290. PEP_STATUS get_all_keys_for_user(PEP_SESSION session,
  291. const char* user_id,
  292. stringlist_t** keys) {
  293. if (!session || EMPTYSTR(user_id) || !keys)
  294. return PEP_ILLEGAL_VALUE;
  295. PEP_STATUS status = PEP_STATUS_OK;
  296. *keys = NULL;
  297. stringlist_t* _kl = NULL;
  298. sqlite3_reset(session->get_all_keys_for_user);
  299. sqlite3_bind_text(session->get_all_keys_for_user, 1, user_id, -1, SQLITE_STATIC);
  300. int result = -1;
  301. while ((result = sqlite3_step(session->get_all_keys_for_user)) == SQLITE_ROW) {
  302. const char* keyres = (const char *) sqlite3_column_text(session->get_all_keys_for_user, 0);
  303. if (keyres) {
  304. if (_kl)
  305. stringlist_add(_kl, keyres);
  306. else
  307. _kl = new_stringlist(keyres);
  308. }
  309. }
  310. if (!_kl)
  311. return PEP_KEY_NOT_FOUND;
  312. *keys = _kl;
  313. sqlite3_reset(session->get_all_keys_for_user);
  314. return status;
  315. }
  316. PEP_STATUS get_user_default_key(PEP_SESSION session, const char* user_id,
  317. char** default_key) {
  318. assert(session);
  319. assert(user_id);
  320. if (!session || !user_id)
  321. return PEP_ILLEGAL_VALUE;
  322. PEP_STATUS status = PEP_STATUS_OK;
  323. // try to get default key for user_data
  324. sqlite3_reset(session->get_user_default_key);
  325. sqlite3_bind_text(session->get_user_default_key, 1, user_id,
  326. -1, SQLITE_STATIC);
  327. const int result = sqlite3_step(session->get_user_default_key);
  328. char* user_fpr = NULL;
  329. if (result == SQLITE_ROW) {
  330. const char* u_fpr =
  331. (char *) sqlite3_column_text(session->get_user_default_key, 0);
  332. if (u_fpr)
  333. user_fpr = strdup(u_fpr);
  334. }
  335. else
  336. status = PEP_GET_KEY_FAILED;
  337. sqlite3_reset(session->get_user_default_key);
  338. *default_key = user_fpr;
  339. return status;
  340. }
  341. // Only call on retrieval of previously stored identity!
  342. // Also, we presume that if the stored_identity was sent in
  343. // without an fpr, there wasn't one in the trust DB for this
  344. // identity.
  345. //
  346. // Will now NOT return passphrase errors, as we tell
  347. // validate_fpr NOT to renew it. And we specifically suppress them
  348. // with "PEP_KEY_UNSUITABLE"
  349. //
  350. PEP_STATUS get_valid_pubkey(PEP_SESSION session,
  351. pEp_identity* stored_identity,
  352. bool* is_identity_default,
  353. bool* is_user_default,
  354. bool* is_address_default,
  355. bool check_blacklist) {
  356. if (!session)
  357. return PEP_ILLEGAL_VALUE;
  358. PEP_STATUS status = PEP_STATUS_OK;
  359. if (!stored_identity || EMPTYSTR(stored_identity->user_id)
  360. || !is_identity_default || !is_user_default || !is_address_default)
  361. return PEP_ILLEGAL_VALUE;
  362. *is_identity_default = *is_user_default = *is_address_default = false;
  363. PEP_comm_type first_reject_comm_type = PEP_ct_key_not_found;
  364. PEP_STATUS first_reject_status = PEP_KEY_NOT_FOUND;
  365. char* stored_fpr = stored_identity->fpr;
  366. // Input: stored identity retrieved from database
  367. // if stored identity contains a default key; if so, we return from here
  368. if (!EMPTYSTR(stored_fpr)) {
  369. // Won't ask for passphrase, won't return PASSPHRASE status
  370. // Because of non-renewal
  371. status = validate_fpr(session, stored_identity, check_blacklist, true, false);
  372. switch (status) {
  373. case PEP_STATUS_OK:
  374. if (!EMPTYSTR(stored_identity->fpr)) {
  375. *is_identity_default = *is_address_default = true;
  376. return status;
  377. }
  378. break;
  379. case PEP_KEY_NOT_FOUND:
  380. break;
  381. default:
  382. first_reject_status = status;
  383. first_reject_comm_type = stored_identity->comm_type;
  384. }
  385. }
  386. // if no valid default stored identity key found
  387. free(stored_identity->fpr);
  388. stored_identity->fpr = NULL;
  389. char* user_fpr = NULL;
  390. status = get_user_default_key(session, stored_identity->user_id, &user_fpr);
  391. if (!EMPTYSTR(user_fpr)) {
  392. // There exists a default key for user, so validate
  393. stored_identity->fpr = user_fpr;
  394. // Won't ask for passphrase, won't return PASSPHRASE status
  395. // Because of non-renewal
  396. status = validate_fpr(session, stored_identity, check_blacklist, true, false);
  397. switch (status) {
  398. case PEP_STATUS_OK:
  399. if (!EMPTYSTR(stored_identity->fpr)) {
  400. *is_user_default = true;
  401. *is_address_default = key_matches_address(session,
  402. stored_identity->address,
  403. stored_identity->fpr);
  404. return status;
  405. }
  406. break;
  407. case PEP_KEY_NOT_FOUND:
  408. break;
  409. default:
  410. if (first_reject_status != PEP_KEY_NOT_FOUND) {
  411. first_reject_status = status;
  412. first_reject_comm_type = stored_identity->comm_type;
  413. }
  414. }
  415. }
  416. // If we got here, there's no usable default.
  417. // status = elect_pubkey(session, stored_identity, check_blacklist);
  418. // if (status == PEP_STATUS_OK) {
  419. // if (!EMPTYSTR(stored_identity->fpr)) {
  420. // // Won't ask for passphrase, won't return PASSPHRASE status
  421. // // Because of non-renewal
  422. // status = validate_fpr(session, stored_identity, false, true, false); // blacklist already filtered of needed
  423. // }
  424. // }
  425. // else if (status != PEP_KEY_NOT_FOUND && first_reject_status != PEP_KEY_NOT_FOUND) {
  426. // first_reject_status = status;
  427. // first_reject_comm_type = stored_identity->comm_type;
  428. // }
  429. switch (first_reject_comm_type) {
  430. case PEP_ct_key_revoked:
  431. case PEP_ct_key_b0rken:
  432. case PEP_ct_key_expired:
  433. case PEP_ct_key_expired_but_confirmed:
  434. case PEP_ct_compromised:
  435. case PEP_ct_mistrusted:
  436. // this only happens when it's all there is
  437. status = first_reject_status;
  438. free(stored_identity->fpr);
  439. stored_identity->fpr = NULL;
  440. stored_identity->comm_type = first_reject_comm_type;
  441. break;
  442. default:
  443. if (check_blacklist && status == PEP_KEY_BLACKLISTED) {
  444. free(stored_identity->fpr);
  445. stored_identity->fpr = NULL;
  446. stored_identity->comm_type = PEP_ct_key_not_found;
  447. }
  448. break;
  449. }
  450. // should never happen, but we will MAKE sure
  451. if (PASS_ERROR(status))
  452. status = PEP_KEY_UNSUITABLE; // renew it on your own time, baby
  453. return status;
  454. }
  455. /**
  456. * @internal
  457. *
  458. * <!-- transfer_ident_lang_and_flags() -->
  459. *
  460. * @brief TODO
  461. *
  462. * @param[in] *new_ident pEp_identity
  463. * @param[in] *stored_ident pEp_identity
  464. *
  465. */
  466. static void transfer_ident_lang_and_flags(pEp_identity* new_ident,
  467. pEp_identity* stored_ident) {
  468. if (!(new_ident && stored_ident))
  469. return;
  470. if (new_ident->lang[0] == 0) {
  471. new_ident->lang[0] = stored_ident->lang[0];
  472. new_ident->lang[1] = stored_ident->lang[1];
  473. new_ident->lang[2] = 0;
  474. }
  475. new_ident->flags = stored_ident->flags;
  476. new_ident->me = new_ident->me || stored_ident->me;
  477. }
  478. /**
  479. * @internal
  480. *
  481. * <!-- adjust_pEp_trust_status() -->
  482. *
  483. * @brief TODO
  484. *
  485. * @param[in] session session handle
  486. * @param[in] *identity pEp_identity
  487. *
  488. */
  489. static void adjust_pEp_trust_status(PEP_SESSION session, pEp_identity* identity) {
  490. assert(session);
  491. assert(identity);
  492. if (!session || !identity ||
  493. identity->comm_type < PEP_ct_strong_but_unconfirmed ||
  494. ((identity->comm_type | PEP_ct_confirmed) == PEP_ct_pEp) )
  495. return;
  496. bool pEp_user;
  497. is_pEp_user(session, identity, &pEp_user);
  498. if (pEp_user) {
  499. PEP_comm_type confirmation_status = identity->comm_type & PEP_ct_confirmed;
  500. identity->comm_type = PEP_ct_pEp_unconfirmed | confirmation_status;
  501. if (identity->major_ver == 0) {
  502. identity->major_ver = 2;
  503. identity->minor_ver = 0;
  504. }
  505. }
  506. }
  507. // NEVER called on an own identity.
  508. // But we also make sure get_valid_pubkey
  509. // and friends NEVER return with a password error.
  510. // (get_valid_pubkey tells validate_fpr not to try renewal)
  511. // Will not return PASSPHRASE errors.
  512. /**
  513. * @internal
  514. *
  515. * <!-- prepare_updated_identity() -->
  516. *
  517. * @brief TODO
  518. *
  519. * @param[in] session session handle
  520. * @param[in] *return_id pEp_identity
  521. * @param[in] *stored_ident pEp_identity
  522. * @param[in] store bool
  523. *
  524. * @retval PEP_STATUS_OK
  525. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  526. * @retval any other value on error
  527. */
  528. static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
  529. pEp_identity* return_id,
  530. pEp_identity* stored_ident,
  531. bool store) {
  532. if (!session || !return_id || !stored_ident)
  533. return PEP_ILLEGAL_VALUE;
  534. PEP_STATUS status;
  535. bool is_identity_default, is_user_default, is_address_default;
  536. bool no_stored_default = EMPTYSTR(stored_ident->fpr);
  537. status = get_valid_pubkey(session, stored_ident,
  538. &is_identity_default,
  539. &is_user_default,
  540. &is_address_default,
  541. false);
  542. bool is_pEp = false;
  543. switch (status) {
  544. // FIXME: can we get memory or DB errors from the above? If so, handle it.
  545. case PEP_STATUS_OK:
  546. if (!EMPTYSTR(stored_ident->fpr)) {
  547. // set identity comm_type from trust db (user_id, FPR)
  548. status = get_trust(session, stored_ident);
  549. PEP_comm_type ct = stored_ident->comm_type;
  550. if (status == PEP_CANNOT_FIND_IDENTITY || ct == PEP_ct_unknown || ct == PEP_ct_key_not_found) {
  551. // This is OK - there is no trust DB entry, but we
  552. // found a key. We won't store this, but we'll
  553. // use it.
  554. ct = PEP_ct_unknown;
  555. status = get_key_rating(session, stored_ident->fpr, &ct);
  556. stored_ident->comm_type = (ct == PEP_ct_unknown ? PEP_ct_key_not_found : ct);
  557. }
  558. }
  559. else if (stored_ident->comm_type == PEP_ct_unknown)
  560. stored_ident->comm_type = PEP_ct_key_not_found;
  561. break;
  562. case PEP_KEY_UNSUITABLE:
  563. status = PEP_STATUS_OK;
  564. // explicit fallthrough
  565. default:
  566. is_pEp_user(session, stored_ident, &is_pEp);
  567. if (is_pEp) {
  568. switch (stored_ident->comm_type) {
  569. case PEP_ct_key_expired:
  570. case PEP_ct_key_expired_but_confirmed:
  571. store = false;
  572. break;
  573. default:
  574. break;
  575. }
  576. }
  577. free(stored_ident->fpr);
  578. stored_ident->fpr = NULL;
  579. stored_ident->comm_type = PEP_ct_key_not_found;
  580. }
  581. free(return_id->fpr);
  582. return_id->fpr = NULL;
  583. if (status == PEP_STATUS_OK && !EMPTYSTR(stored_ident->fpr))
  584. return_id->fpr = strdup(stored_ident->fpr);
  585. return_id->comm_type = stored_ident->comm_type;
  586. // We patch the DB with the input username, but if we didn't have
  587. // one, we pull it out of storage if available.
  588. if (!EMPTYSTR(stored_ident->username)) {
  589. if (!EMPTYSTR(return_id->username) &&
  590. (strcasecmp(return_id->username, return_id->address) == 0)) {
  591. free(return_id->username);
  592. return_id->username = NULL;
  593. }
  594. if (EMPTYSTR(return_id->username)) {
  595. free(return_id->username);
  596. return_id->username = strdup(stored_ident->username);
  597. }
  598. }
  599. else {
  600. if (EMPTYSTR(return_id->username))
  601. return_id->username = strdup(return_id->address);
  602. }
  603. return_id->me = stored_ident->me;
  604. return_id->major_ver = stored_ident->major_ver;
  605. return_id->minor_ver = stored_ident->minor_ver;
  606. // FIXME: Do we ALWAYS do this? We probably should...
  607. if (EMPTYSTR(return_id->user_id)) {
  608. free(return_id->user_id);
  609. return_id->user_id = strdup(stored_ident->user_id);
  610. }
  611. adjust_pEp_trust_status(session, return_id);
  612. // Call set_identity() to store
  613. if (store && (is_identity_default || is_user_default) &&
  614. is_address_default) {
  615. // if we got an fpr which is default for either user
  616. // or identity AND is valid for this address, set in DB
  617. // as default
  618. status = set_identity(session, return_id);
  619. }
  620. else if (store && no_stored_default && !EMPTYSTR(return_id->fpr)
  621. && return_id->comm_type != PEP_ct_key_revoked
  622. && return_id->comm_type != PEP_ct_key_expired
  623. && return_id->comm_type != PEP_ct_key_expired_but_confirmed
  624. && return_id->comm_type != PEP_ct_mistrusted
  625. && return_id->comm_type != PEP_ct_key_b0rken) {
  626. // We would have stored this anyway for a first-time elected key. We just have an ident w/ no default already.
  627. status = set_identity(session, return_id);
  628. }
  629. else { // this is a key other than the default, but there IS a default (FIXME: fdik, do we really want behaviour below?)
  630. // Store without default fpr/ct, but return the fpr and ct
  631. // for current use
  632. char* save_fpr = return_id->fpr;
  633. PEP_comm_type save_ct = return_id->comm_type;
  634. return_id->fpr = NULL;
  635. return_id->comm_type = PEP_ct_unknown;
  636. if (store) {
  637. PEP_STATUS save_status = status;
  638. status = set_identity(session, return_id);
  639. if (save_status != PEP_STATUS_OK)
  640. status = save_status;
  641. }
  642. return_id->fpr = save_fpr;
  643. return_id->comm_type = save_ct;
  644. }
  645. transfer_ident_lang_and_flags(return_id, stored_ident);
  646. return_id->enc_format = stored_ident->enc_format;
  647. if (return_id->comm_type == PEP_ct_unknown)
  648. return_id->comm_type = PEP_ct_key_not_found;
  649. return status;
  650. }
  651. // Should not return PASSPHRASE errors because we force
  652. // calls that can cause key renewal not to.
  653. DYNAMIC_API PEP_STATUS update_identity(
  654. PEP_SESSION session, pEp_identity * identity
  655. )
  656. {
  657. PEP_STATUS status = PEP_STATUS_OK;
  658. assert(session);
  659. assert(identity);
  660. assert(!EMPTYSTR(identity->address));
  661. if (!(session && identity && !EMPTYSTR(identity->address)))
  662. return PEP_ILLEGAL_VALUE;
  663. //
  664. // Record some information about the input identity so that we don't keep
  665. // evaluating it
  666. //
  667. bool is_own_user = identity->me;
  668. bool input_has_user_id = !EMPTYSTR(identity->user_id);
  669. bool input_has_username = !EMPTYSTR(identity->username);
  670. bool input_has_real_id = input_has_user_id ? (strstr(identity->user_id, "TOFU_") != identity->user_id) : false;
  671. bool input_name_is_addr = input_has_username ? strcmp(identity->username, identity->address) == 0 : false;
  672. bool weak_input_name = input_name_is_addr || !input_has_username;
  673. char* default_own_id = NULL;
  674. pEp_identity* stored_ident = NULL;
  675. status = get_default_own_userid(session, &default_own_id);
  676. if (status == PEP_STATUS_OK || status == PEP_CANNOT_FIND_IDENTITY)
  677. status = PEP_STATUS_OK;
  678. else
  679. goto pEp_free;
  680. // To be clear, if an own identity comes in here, the only way we will accept
  681. // it is if the caller did not KNOW this, as indicated by the lack of a known
  682. // own user_id and identity->me being false.
  683. //
  684. // IF either of these are set, then the call will fail. If, however, we get
  685. // an identity which simply has the own address on it, we'll kindly call a read-only
  686. // version of myself.
  687. if (!is_own_user) {
  688. if (default_own_id) {
  689. if (input_has_user_id) {
  690. if (strcmp(default_own_id, identity->user_id) == 0) {
  691. is_own_user = true;
  692. }
  693. else {
  694. char* alias = NULL;
  695. if (get_userid_alias_default(session, identity->user_id, &alias) == PEP_STATUS_OK) {
  696. if (alias && strcmp(default_own_id, alias) == 0)
  697. is_own_user = true;
  698. free(alias);
  699. }
  700. }
  701. }
  702. else {
  703. // Check if own address. For now, this is a special case;
  704. // we try to require apps to send in user_ids, but must prevent
  705. // writes to an own identity from within THIS function
  706. // NOTE: These semantics MAY CHANGE.
  707. bool _own_addr = false;
  708. is_own_address(session, identity->address, &_own_addr);
  709. if (_own_addr) {
  710. free(identity->user_id);
  711. identity->user_id = strdup(default_own_id);
  712. // Do not renew, do not generate
  713. return _myself(session, identity, false, false, false, true);
  714. }
  715. }
  716. }
  717. // Otherwise, we don't even HAVE an own user yet, so we're ok.
  718. }
  719. if (is_own_user) {
  720. free(default_own_id);
  721. return PEP_ILLEGAL_VALUE;
  722. }
  723. // We have, at least, an address.
  724. // Retrieve stored identity information!
  725. //////////////////////////////////////////////////////////////////////////////////////////////////////
  726. // If we can get a starting identity from the database, do it. If we have a user_id (thank you, users),
  727. // this is pretty simple.
  728. //
  729. // Otherwise, we double-check that someone didn't pass in an own address (hey, if you don't give us a
  730. // user_id, we're have to guess somehow, and treating own identities like partner identities is dangerous).
  731. //////////////////////////////////////////////////////////////////////////////////////////////////////
  732. if (input_has_user_id) {
  733. // (we're gonna update the trust/fpr anyway, so we use the no-fpr-from-trust-db variant)
  734. // * do get_identity() to retrieve stored identity information
  735. status = get_identity_without_trust_check(session, identity->address, identity->user_id, &stored_ident);
  736. }
  737. else { // see if we perhaps own this user
  738. if (default_own_id) {
  739. status = get_identity(session,
  740. identity->address,
  741. default_own_id,
  742. &stored_ident);
  743. }
  744. }
  745. //////////////////////////////////////////////////////////////////////////////////////////////////////
  746. // If we're unable to get a starting stored ID, we now need to try to get IDs which match the address.
  747. // Should we find them, we go through the list and try to find an acceptable one by evaluating the
  748. // following properties (not in order of priority, and not for every case - the logic here is a mess):
  749. //
  750. // 1. Did the input have a user_id?
  751. // 2. Did the input hava a username?
  752. // 3. Is the input user_id a real id?
  753. // 4. Is the stored user_id a real id?
  754. // 5. Does the stored user_id have a username?
  755. // 6. Do the names match?
  756. //
  757. // Based on this, if we find an acceptable candidate, we do one:
  758. //
  759. // 1. Replace the global DB user_id with the input user_id and patch the stored identity's user_id
  760. // (this may be different than 1, though in practice it seems we always do both)
  761. // 2. Patch the output identity's user_id from the stored identity
  762. //
  763. // If we find none, in the case if the has-username-but-no-user_id input case, we'll try a TOFU id
  764. // fetch before giving up on stored identity candidates.
  765. //
  766. // Acceptable candidates are then passed to prepare_update_identity which will patch usernames and
  767. // find any applicable keys.
  768. //
  769. // Unacceptable candidates will then have minimal record information entered depending on how much
  770. // came in in the input, TOFU user_ids created when needed, and a new record placed in the DB
  771. // accordingly.
  772. //
  773. if (!stored_ident) {
  774. identity_list* id_list = NULL;
  775. status = get_identities_by_address(session, identity->address, &id_list);
  776. if (id_list) {
  777. identity_list* stored_curr = id_list;
  778. // Ok, here's where we search for stored identities and try to find a candidate.
  779. while (stored_curr) {
  780. // Ok, this is where the above code fun begins. Let's get some information about the identity.
  781. pEp_identity* candidate = stored_curr->ident;
  782. if (candidate) {
  783. char* candidate_id = candidate->user_id;
  784. // this_uid should never be NULL, as this is half of the ident
  785. // DB primary key
  786. assert(!EMPTYSTR(candidate_id));
  787. // grab some information about the stored identity
  788. bool candidate_has_real_id = strstr(candidate_id, "TOFU_") != candidate_id;
  789. bool candidate_has_username = !EMPTYSTR(candidate->username);
  790. bool candidate_name_is_addr = candidate_has_username ? strcmp(candidate->address, candidate->username) == 0 : false;
  791. bool weak_candidate_name = !candidate_has_username || candidate_name_is_addr;
  792. bool names_match = (weak_candidate_name && weak_input_name) ||
  793. ((input_has_username && candidate_has_username) &&
  794. (strcmp(identity->username, candidate->username) == 0));
  795. // This is where the optimisation gets a little weird:
  796. //
  797. // Decide whether to accept and patch the database and stored id from the input,
  798. // Accept and patch the input id from the database, or reject and go to the next
  799. // one in the list
  800. //
  801. // This is unnecessary, but I think the terms need to be descriptive where possible
  802. bool input_addr_only = !input_has_username && !input_has_user_id;
  803. bool candidate_id_best = candidate_has_real_id && !input_has_real_id;
  804. bool input_id_best = input_has_real_id && !candidate_has_real_id;
  805. bool patch_input_id_conditions = input_has_user_id || names_match || weak_candidate_name;
  806. if (input_addr_only || (candidate_id_best && patch_input_id_conditions)) {
  807. identity->user_id = strdup(candidate_id);
  808. assert(identity->user_id);
  809. if (!identity->user_id)
  810. goto enomem;
  811. stored_ident = identity_dup(candidate);
  812. break;
  813. }
  814. else if (input_id_best && (names_match || (input_has_username && weak_candidate_name))) {
  815. // Replace the TOFU db in the database with the input ID globally
  816. status = replace_userid(session,
  817. candidate_id,
  818. identity->user_id);
  819. if (status != PEP_STATUS_OK) {
  820. free_identity_list(id_list);
  821. free(default_own_id);
  822. return status;
  823. }
  824. // Reflect the change we just made to the DB
  825. free(candidate->user_id);
  826. candidate->user_id = strdup(identity->user_id);
  827. stored_ident = identity_dup(candidate);
  828. break;
  829. } // End else if
  830. // Else, we reject this candidate and try the next one, if there is one.
  831. stored_curr = stored_curr->next;
  832. }
  833. // Ok, we've checked all of the candidates, and if there's a stored identity, there's a duplicate.
  834. // Freeeeeeee...
  835. free_identity_list(id_list);
  836. }
  837. }
  838. // If, by here, there is no user id on the identity, we put one on there.
  839. // We've found any non-TOFU one we're going to find, so if this is empty,
  840. // We don't have a stored ident.
  841. if (EMPTYSTR(identity->user_id)) {
  842. identity->user_id = calloc(1, strlen(identity->address) + 6);
  843. if (!identity->user_id)
  844. goto enomem;
  845. snprintf(identity->user_id, strlen(identity->address) + 6,
  846. "TOFU_%s", identity->address);
  847. // Try one last time to see if there is an ident for us with a TOFU id, if there was no ID but there
  848. // was a usernames
  849. if (input_has_username) {
  850. status = get_identity(session,
  851. identity->address,
  852. identity->user_id,
  853. &stored_ident);
  854. }
  855. }
  856. }
  857. //
  858. // Either update the identity (and possibly DB to reflect stored ident information, or
  859. // create a new identity and store it.
  860. //
  861. if (status == PEP_STATUS_OK && stored_ident) {
  862. // An identity was available.
  863. // Call will patch the username where needed and
  864. // get a valid default key (for ident or user)
  865. status = prepare_updated_identity(session,
  866. identity,
  867. stored_ident, true);
  868. }
  869. else { // No stored ident. We're done.
  870. // If we needed TOFU, we've taken care of the ID above.
  871. if (EMPTYSTR(identity->username)) { // currently, not after messing around
  872. free(identity->username);
  873. identity->username = strdup(identity->address);
  874. if (!identity->username)
  875. goto enomem;
  876. }
  877. free(identity->fpr);
  878. identity->fpr = NULL;
  879. identity->comm_type = PEP_ct_unknown;
  880. adjust_pEp_trust_status(session, identity);
  881. status = set_identity(session, identity);
  882. // This is ONLY for the return value - VB confirms we should tell the user we didn't find a key
  883. if (identity->comm_type == PEP_ct_unknown)
  884. identity->comm_type = PEP_ct_key_not_found;
  885. }
  886. // VB says, and I quote, "that is not implemented and no one is using it right now"
  887. // about this bit. So, um, you're forewarned.
  888. if (identity->comm_type != PEP_ct_compromised &&
  889. identity->comm_type < PEP_ct_strong_but_unconfirmed)
  890. if (session->examine_identity)
  891. session->examine_identity(identity, session->examine_management);
  892. goto pEp_free;
  893. enomem:
  894. status = PEP_OUT_OF_MEMORY;
  895. pEp_free:
  896. free(default_own_id);
  897. free_identity(stored_ident);
  898. return status;
  899. }
  900. /**
  901. * @internal
  902. *
  903. * <!-- elect_ownkey() -->
  904. *
  905. * @brief TODO
  906. *
  907. * @param[in] session session handle
  908. * @param[in] *identity pEp_identity
  909. *
  910. * @retval PEP_STATUS_OK
  911. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  912. * @retval PEP_OUT_OF_MEMORY out of memory
  913. * @retval any other value on error
  914. */
  915. PEP_STATUS elect_ownkey(
  916. PEP_SESSION session, pEp_identity * identity
  917. )
  918. {
  919. if (!(session && identity))
  920. return PEP_ILLEGAL_VALUE;
  921. PEP_STATUS status;
  922. stringlist_t *keylist = NULL;
  923. free(identity->fpr);
  924. identity->fpr = NULL;
  925. status = find_private_keys(session, identity->address, &keylist);
  926. assert(status != PEP_OUT_OF_MEMORY);
  927. if (status == PEP_OUT_OF_MEMORY)
  928. return PEP_OUT_OF_MEMORY;
  929. if (keylist != NULL && keylist->value != NULL)
  930. {
  931. char *_fpr = NULL;
  932. identity->comm_type = PEP_ct_unknown;
  933. stringlist_t *_keylist;
  934. for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
  935. bool is_own = false;
  936. status = own_key_is_listed(session, _keylist->value, &is_own);
  937. assert(status == PEP_STATUS_OK);
  938. if (status != PEP_STATUS_OK) {
  939. free_stringlist(keylist);
  940. return status;
  941. }
  942. if (is_own)
  943. {
  944. PEP_comm_type _comm_type_key;
  945. status = get_key_rating(session, _keylist->value, &_comm_type_key);
  946. assert(status != PEP_OUT_OF_MEMORY);
  947. if (status == PEP_OUT_OF_MEMORY) {
  948. free_stringlist(keylist);
  949. return PEP_OUT_OF_MEMORY;
  950. }
  951. if (_comm_type_key != PEP_ct_compromised &&
  952. _comm_type_key != PEP_ct_unknown)
  953. {
  954. if (identity->comm_type == PEP_ct_unknown ||
  955. _comm_type_key > identity->comm_type)
  956. {
  957. identity->comm_type = _comm_type_key;
  958. _fpr = _keylist->value;
  959. }
  960. }
  961. }
  962. }
  963. if (_fpr)
  964. {
  965. identity->fpr = strdup(_fpr);
  966. assert(identity->fpr);
  967. if (identity->fpr == NULL)
  968. {
  969. free_stringlist(keylist);
  970. return PEP_OUT_OF_MEMORY;
  971. }
  972. }
  973. free_stringlist(keylist);
  974. }
  975. return PEP_STATUS_OK;
  976. }
  977. /**
  978. * @internal
  979. *
  980. * <!-- _has_usable_priv_key() -->
  981. *
  982. * @brief TODO
  983. *
  984. * @param[in] session session handle
  985. * @param[in] *fpr char
  986. * @param[in] *is_usable bool
  987. *
  988. * @retval PEP_STATUS_OK
  989. * @retval PEP_ILLEGAL_VALUE illegal parameter values
  990. * @retval any other value on error
  991. */
  992. PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
  993. bool* is_usable) {
  994. bool has_private = false;
  995. PEP_STATUS status = contains_priv_key(session, fpr, &has_private);
  996. *is_usable = has_private;
  997. return status;
  998. }
  999. PEP_STATUS _myself(PEP_SESSION session,
  1000. pEp_identity * identity,
  1001. bool do_keygen,
  1002. bool do_renew,
  1003. bool ignore_flags,
  1004. bool read_only)
  1005. {
  1006. PEP_STATUS status;
  1007. assert(session);
  1008. assert(identity);
  1009. assert(!EMPTYSTR(identity->address));
  1010. if (!session || !identity || EMPTYSTR(identity->address))
  1011. return PEP_ILLEGAL_VALUE;
  1012. // this leads to crashes otherwise
  1013. if (!(identity->user_id && identity->user_id[0])) {
  1014. free(identity->user_id);
  1015. identity->user_id = strdup(PEP_OWN_USERID);
  1016. assert(identity->user_id);
  1017. if (!identity->user_id)
  1018. return PEP_OUT_OF_MEMORY;
  1019. }
  1020. // Cache the input username, if there is one and it's not read_only
  1021. char* cached_input_username = NULL;
  1022. if (!read_only && identity->username) {
  1023. cached_input_username = strdup(identity->username);
  1024. if (!cached_input_username)
  1025. return PEP_OUT_OF_MEMORY;
  1026. }
  1027. pEp_identity *stored_identity = NULL;
  1028. char* revoked_fpr = NULL;
  1029. bool valid_key_found = false;
  1030. char* default_own_id = NULL;
  1031. status = get_default_own_userid(session, &default_own_id);
  1032. // Deal with non-default user_ids.
  1033. // FIXME: if non-default and read-only, reject totally?
  1034. if (default_own_id && strcmp(default_own_id, identity->user_id) != 0) {
  1035. if (read_only) {
  1036. free(identity->user_id);
  1037. identity->user_id = strdup(default_own_id);
  1038. assert(identity->user_id);
  1039. if (!identity->user_id)
  1040. return PEP_OUT_OF_MEMORY;
  1041. }
  1042. else {
  1043. status = set_userid_alias(session, default_own_id, identity->user_id);
  1044. // Do we want this to be fatal? For now, we'll do it...
  1045. if (status != PEP_STATUS_OK)
  1046. goto pEp_free;
  1047. free(identity->user_id);
  1048. identity->user_id = strdup(default_own_id);
  1049. assert(identity->user_id);
  1050. if (identity->user_id == NULL) {
  1051. status = PEP_OUT_OF_MEMORY;
  1052. goto pEp_free;
  1053. }
  1054. }
  1055. }
  1056. // NOTE: IF WE DON'T YET HAVE AN OWN_ID, WE IGNORE REFERENCES TO THIS ADDRESS IN THE
  1057. // DB (WHICH MAY HAVE BEEN SET BEFORE MYSELF WAS CALLED BY RECEIVING AN EMAIL FROM
  1058. // THIS ADDRESS), AS IT IS NOT AN OWN_IDENTITY AND HAS NO INFORMATION WE NEED OR WHAT TO
  1059. // SET FOR MYSELF
  1060. // Ok, so now, set up the own_identity:
  1061. identity->comm_type = PEP_ct_pEp;
  1062. identity->me = true;
  1063. if(ignore_flags)
  1064. identity->flags = 0;
  1065. // Let's see if we have an identity record in the DB for
  1066. // this user_id + address
  1067. // DEBUG_LOG("myself", "debug", identity->address);
  1068. // This will grab the actual flags from the db
  1069. status = get_identity(session,
  1070. identity->address,
  1071. identity->user_id,
  1072. &stored_identity);
  1073. assert(status != PEP_OUT_OF_MEMORY);
  1074. if (status == PEP_OUT_OF_MEMORY) {
  1075. status = PEP_OUT_OF_MEMORY;
  1076. goto pEp_free;
  1077. }
  1078. // Set usernames - priority is input username > stored name > address
  1079. // If there's an input username, we always patch the username with that
  1080. // input.
  1081. // N.B. there was an || read_only here, but why? read_only ONLY means
  1082. // we don't write to the DB! So... removed. But how this managed to work
  1083. // before I don't know.
  1084. if (EMPTYSTR(identity->username)) {
  1085. bool stored_uname = (stored_identity && !EMPTYSTR(stored_identity->username));
  1086. char* uname = (stored_uname ? stored_identity->username : identity->address);
  1087. if (uname) {
  1088. free(identity->username);
  1089. identity->username = strdup(uname);
  1090. assert(identity->username);
  1091. if (identity->username == NULL) {
  1092. status = PEP_OUT_OF_MEMORY;
  1093. goto pEp_free;
  1094. }
  1095. }
  1096. }
  1097. // ignore input fpr
  1098. if (identity->fpr) {
  1099. free(identity->fpr);
  1100. identity->fpr = NULL;
  1101. }
  1102. // check stored identity
  1103. if (stored_identity) {
  1104. if (!EMPTYSTR(stored_identity->fpr)) {
  1105. // Fall back / retrieve
  1106. status = validate_fpr(session, stored_identity, false, true, do_renew);
  1107. switch (status) {
  1108. // Only possible if we called this with do_renew = true
  1109. case PEP_OUT_OF_MEMORY:
  1110. case PEP_PASSPHRASE_REQUIRED:
  1111. case PEP_WRONG_PASSPHRASE:
  1112. goto pEp_free;
  1113. case PEP_STATUS_OK:
  1114. if (stored_identity->comm_type >= PEP_ct_strong_but_unconfirmed) {
  1115. identity->fpr = strdup(stored_identity->fpr);
  1116. assert(identity->fpr);
  1117. if (!identity->fpr) {
  1118. status = PEP_OUT_OF_MEMORY;
  1119. goto pEp_free;
  1120. }
  1121. valid_key_found = true;
  1122. }
  1123. else {
  1124. bool revoked = false;
  1125. status = key_revoked(session, stored_identity->fpr, &revoked);
  1126. if (status)
  1127. goto pEp_free;
  1128. if (revoked) {
  1129. revoked_fpr = strdup(stored_identity->fpr);
  1130. assert(revoked_fpr);
  1131. if (!revoked_fpr) {
  1132. status = PEP_OUT_OF_MEMORY;
  1133. goto pEp_free;
  1134. }
  1135. }
  1136. }
  1137. break;
  1138. default:
  1139. break;
  1140. }
  1141. }
  1142. // reconcile language, flags
  1143. transfer_ident_lang_and_flags(identity, stored_identity);
  1144. }
  1145. // Nothing left to do but generate a key
  1146. if (!valid_key_found) {
  1147. if (!do_keygen || read_only)
  1148. status = PEP_GET_KEY_FAILED;
  1149. else {
  1150. // / DEBUG_LOG("Generating key pair", "debug", identity->address);
  1151. free(identity->fpr);
  1152. identity->fpr = NULL;
  1153. status = generate_keypair(session, identity);
  1154. assert(status != PEP_OUT_OF_MEMORY);
  1155. if (status == PEP_PASSPHRASE_FOR_NEW_KEYS_REQUIRED)
  1156. goto pEp_free;
  1157. if (status != PEP_STATUS_OK) {
  1158. char buf[11];
  1159. snprintf(buf, 11, "%d", status); // uh, this is kludgey. FIXME
  1160. // DEBUG_LOG("Generating key pair failed", "debug", buf);
  1161. }
  1162. else {
  1163. valid_key_found = true;
  1164. if (revoked_fpr) {
  1165. status = set_revoked(session, revoked_fpr,
  1166. stored_identity->fpr, time(NULL));
  1167. assert(status == PEP_STATUS_OK);
  1168. }
  1169. }
  1170. }
  1171. }
  1172. if (valid_key_found</