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.

481 lines
16 KiB

  1. // This file is under GNU General Public License 3.0
  2. // see LICENSE.txt
  3. #include "pEp_internal.h"
  4. #include "dynamic_api.h"
  5. #include "message_api.h"
  6. #include <string.h>
  7. #include <stdlib.h>
  8. PEP_STATUS has_key_reset_been_sent(
  9. PEP_SESSION session,
  10. const char* user_id,
  11. const char* revoked_fpr,
  12. bool* contacted)
  13. {
  14. assert(session);
  15. assert(contacted);
  16. assert(user_id);
  17. assert(revoked_fpr);
  18. assert(!EMPTYSTR(user_id));
  19. if (!session || !contacted || EMPTYSTR(revoked_fpr) || EMPTYSTR(user_id))
  20. return PEP_ILLEGAL_VALUE;
  21. *contacted = false;
  22. char* alias_default = NULL;
  23. PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
  24. if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
  25. free(alias_default);
  26. alias_default = strdup(user_id);
  27. }
  28. sqlite3_reset(session->was_id_for_revoke_contacted);
  29. sqlite3_bind_text(session->was_id_for_revoke_contacted, 1, revoked_fpr, -1,
  30. SQLITE_STATIC);
  31. sqlite3_bind_text(session->was_id_for_revoke_contacted, 2, user_id, -1,
  32. SQLITE_STATIC);
  33. int result = sqlite3_step(session->was_id_for_revoke_contacted);
  34. switch (result) {
  35. case SQLITE_ROW: {
  36. *contacted = (sqlite3_column_int(session->was_id_for_revoke_contacted, 0) != 0);
  37. break;
  38. }
  39. default:
  40. sqlite3_reset(session->was_id_for_revoke_contacted);
  41. free(alias_default);
  42. return PEP_UNKNOWN_DB_ERROR;
  43. }
  44. sqlite3_reset(session->was_id_for_revoke_contacted);
  45. return PEP_STATUS_OK;
  46. }
  47. //static const char *sql_set_revoke_contact_as_notified =
  48. // "insert or replace into revocation_contact_list(fpr, contact_id) values (?1, ?2) ;";
  49. PEP_STATUS set_reset_contact_notified(
  50. PEP_SESSION session,
  51. const char* revoke_fpr,
  52. const char* contact_id
  53. )
  54. {
  55. PEP_STATUS status = PEP_STATUS_OK;
  56. assert(session && !EMPTYSTR(revoke_fpr) && !EMPTYSTR(contact_id));
  57. if (!session || EMPTYSTR(revoke_fpr) || EMPTYSTR(contact_id))
  58. return PEP_ILLEGAL_VALUE;
  59. sqlite3_reset(session->set_revoke_contact_as_notified);
  60. sqlite3_bind_text(session->set_revoke_contact_as_notified, 1, revoke_fpr, -1,
  61. SQLITE_STATIC);
  62. sqlite3_bind_text(session->set_revoke_contact_as_notified, 2, contact_id, -1,
  63. SQLITE_STATIC);
  64. int result;
  65. result = sqlite3_step(session->set_revoke_contact_as_notified);
  66. switch (result) {
  67. case SQLITE_DONE:
  68. status = PEP_STATUS_OK;
  69. break;
  70. default:
  71. status = PEP_UNKNOWN_DB_ERROR;
  72. }
  73. sqlite3_reset(session->set_revoke_contact_as_notified);
  74. return status;
  75. }
  76. PEP_STATUS receive_key_reset(PEP_SESSION session,
  77. message* reset_msg) {
  78. if (!session || !reset_msg)
  79. return PEP_ILLEGAL_VALUE;
  80. pEp_identity* sender_id = reset_msg->from;
  81. if (!sender_id)
  82. return PEP_MALFORMED_KEY_RESET_MSG;
  83. PEP_STATUS status = update_identity(session, sender_id);
  84. if (!sender_id->user_id)
  85. return PEP_UNKNOWN_ERROR;
  86. if (is_me(session, sender_id))
  87. return PEP_ILLEGAL_VALUE;
  88. if (!reset_msg->longmsg || strncmp(reset_msg->longmsg, "OLD: ", 5) != 0)
  89. return PEP_MALFORMED_KEY_RESET_MSG;
  90. status = PEP_STATUS_OK;
  91. char* old_fpr = NULL;
  92. char* new_fpr = NULL;
  93. stringlist_t* keylist = NULL;
  94. pEp_identity* temp_ident = identity_dup(sender_id);
  95. if (!temp_ident) {
  96. status = PEP_OUT_OF_MEMORY;
  97. goto pEp_free;
  98. }
  99. char* rest = NULL;
  100. char* p = strtok_r(reset_msg->longmsg, "\r\n", &rest);
  101. if (!EMPTYSTR(p + 5))
  102. old_fpr = strdup(p + 5);
  103. else {
  104. status = PEP_MALFORMED_KEY_RESET_MSG;
  105. goto pEp_free;
  106. }
  107. bool own_key = false;
  108. status = is_own_key(session, old_fpr, &own_key);
  109. if (own_key) {
  110. // Nope, no one can make us our own default. If we want to do that,
  111. // that's keysync, NOT key reset.
  112. status = PEP_ILLEGAL_VALUE;
  113. goto pEp_free;
  114. }
  115. p = strtok_r(NULL, "\r\n", &rest);
  116. if (strncmp(p, "NEW: ", 5) != 0 || EMPTYSTR(p + 5)) {
  117. status = PEP_MALFORMED_KEY_RESET_MSG;
  118. goto pEp_free;
  119. }
  120. new_fpr = strdup(p + 5);
  121. // Reset the original key
  122. status = key_reset(session, old_fpr, temp_ident);
  123. if (status != PEP_STATUS_OK)
  124. goto pEp_free;
  125. status = find_keys(session, new_fpr, &keylist);
  126. if (status != PEP_STATUS_OK)
  127. goto pEp_free;
  128. if (!keylist) {
  129. status = PEP_KEY_NOT_FOUND;
  130. goto pEp_free;
  131. }
  132. // alright, we've checked as best we can. Let's set that baby.
  133. sender_id->fpr = new_fpr;
  134. // This only sets as the default, does NOT TRUST IN ANY WAY
  135. sender_id->comm_type = sender_id->comm_type & (~PEP_ct_confirmed);
  136. status = set_identity(session, sender_id);
  137. sender_id->fpr = NULL; // ownership for free
  138. pEp_free:
  139. free_stringlist(keylist);
  140. free(old_fpr);
  141. free(new_fpr);
  142. free_identity(temp_ident);
  143. return status;
  144. }
  145. PEP_STATUS create_standalone_key_reset_message(PEP_SESSION session,
  146. message** dst,
  147. pEp_identity* recip,
  148. const char* old_fpr,
  149. const char* new_fpr) {
  150. if (!dst || !recip->user_id || !recip->address)
  151. return PEP_ILLEGAL_VALUE;
  152. if (!old_fpr || !new_fpr)
  153. return PEP_ILLEGAL_VALUE;
  154. *dst = NULL;
  155. // Get own identity user has corresponded with
  156. pEp_identity* own_identity = NULL;
  157. PEP_STATUS status = get_own_ident_for_contact_id(session,
  158. recip,
  159. &own_identity);
  160. if (status != PEP_STATUS_OK)
  161. return status;
  162. message* reset_message = new_message(PEP_dir_outgoing);
  163. reset_message->from = own_identity;
  164. reset_message->to = new_identity_list(identity_dup(recip)); // ?
  165. const char* oldtag = "OLD: ";
  166. const char* newtag = "\nNEW: ";
  167. const size_t taglens = 11;
  168. size_t full_len = taglens + strlen(old_fpr) + strlen(new_fpr) + 2; // \n and \0
  169. char* longmsg = calloc(full_len, 1);
  170. strlcpy(longmsg, oldtag, full_len);
  171. strlcat(longmsg, old_fpr, full_len);
  172. strlcat(longmsg, newtag, full_len);
  173. strlcat(longmsg, new_fpr, full_len);
  174. strlcat(longmsg, "\n", full_len);
  175. reset_message->longmsg = longmsg;
  176. reset_message->shortmsg = strdup("Key reset");
  177. message* output_msg = NULL;
  178. status = encrypt_message(session, reset_message, NULL,
  179. &output_msg, PEP_enc_PGP_MIME,
  180. PEP_encrypt_flag_key_reset_only);
  181. if (status == PEP_STATUS_OK)
  182. *dst = output_msg;
  183. free_message(reset_message);
  184. return status;
  185. }
  186. PEP_STATUS send_key_reset_to_recents(PEP_SESSION session,
  187. const char* old_fpr,
  188. const char* new_fpr) {
  189. assert(old_fpr);
  190. assert(new_fpr);
  191. assert(session);
  192. assert(session->messageToSend);
  193. if (!session || !old_fpr || !new_fpr)
  194. return PEP_ILLEGAL_VALUE;
  195. messageToSend_t send_cb = session->messageToSend;
  196. if (!send_cb)
  197. return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
  198. identity_list* recent_contacts = NULL;
  199. message* reset_msg = NULL;
  200. PEP_STATUS status = get_last_contacted(session, &recent_contacts);
  201. if (status != PEP_STATUS_OK)
  202. goto pEp_free;
  203. identity_list* curr_id_ptr = recent_contacts;
  204. for (curr_id_ptr = recent_contacts; curr_id_ptr; curr_id_ptr = curr_id_ptr->next) {
  205. pEp_identity* curr_id = curr_id_ptr->ident;
  206. if (!curr_id)
  207. break;
  208. const char* user_id = curr_id->user_id;
  209. // Should be impossible, but?
  210. if (!user_id)
  211. continue;
  212. // Check if it's us - if so, pointless...
  213. if (is_me(session, curr_id))
  214. continue;
  215. // Check if they've already been told - this shouldn't be the case, but...
  216. bool contacted = false;
  217. status = has_key_reset_been_sent(session, user_id, old_fpr, &contacted);
  218. if (status != PEP_STATUS_OK)
  219. goto pEp_free;
  220. if (contacted)
  221. continue;
  222. // if not, make em a message
  223. reset_msg = NULL;
  224. status = create_standalone_key_reset_message(session,
  225. &reset_msg,
  226. curr_id,
  227. old_fpr,
  228. new_fpr);
  229. if (status == PEP_CANNOT_FIND_IDENTITY) { // this is ok, just means we never mailed them
  230. status = PEP_STATUS_OK;
  231. continue;
  232. }
  233. if (status != PEP_STATUS_OK) {
  234. free(reset_msg);
  235. goto pEp_free;
  236. }
  237. // insert into queue
  238. status = send_cb(reset_msg);
  239. if (status != PEP_STATUS_OK) {
  240. free(reset_msg);
  241. goto pEp_free;
  242. }
  243. // Put into notified DB
  244. status = set_reset_contact_notified(session, old_fpr, user_id);
  245. if (status != PEP_STATUS_OK)
  246. goto pEp_free;
  247. }
  248. pEp_free:
  249. free_identity_list(recent_contacts);
  250. return status;
  251. }
  252. DYNAMIC_API PEP_STATUS key_reset(
  253. PEP_SESSION session,
  254. const char* key_id,
  255. pEp_identity* ident
  256. )
  257. {
  258. if (!session)
  259. return PEP_ILLEGAL_VALUE;
  260. PEP_STATUS status = PEP_STATUS_OK;
  261. char* fpr_copy = NULL;
  262. char* own_id = NULL;
  263. char* new_key = NULL;
  264. identity_list* key_idents = NULL;
  265. stringlist_t* keys = NULL;
  266. if (!EMPTYSTR(key_id)) {
  267. fpr_copy = strdup(key_id);
  268. if (!fpr_copy)
  269. return PEP_OUT_OF_MEMORY;
  270. }
  271. if (!ident) {
  272. // Get list of own identities
  273. status = get_default_own_userid(session, &own_id);
  274. if (status != PEP_STATUS_OK)
  275. goto pEp_free;
  276. if (EMPTYSTR(fpr_copy)) {
  277. status = get_all_keys_for_user(session, own_id, &keys);
  278. if (status == PEP_STATUS_OK) {
  279. stringlist_t* curr_key;
  280. for (curr_key = keys; curr_key && curr_key->value; curr_key = curr_key->next) {
  281. status = key_reset(session, curr_key->value, NULL);
  282. if (status != PEP_STATUS_OK)
  283. break;
  284. }
  285. }
  286. goto pEp_free;
  287. } // otherwise, we have a specific fpr to process
  288. // fpr_copy exists, so... let's go.
  289. // Process own identities with this fpr
  290. status = get_identities_by_main_key_id(session, fpr_copy, &key_idents);
  291. if (status == PEP_STATUS_OK) {
  292. // have ident list, or should
  293. identity_list* curr_ident;
  294. for (curr_ident = key_idents; curr_ident && curr_ident->ident;
  295. curr_ident = curr_ident->next) {
  296. pEp_identity* this_identity = curr_ident->ident;
  297. status = key_reset(session, fpr_copy, this_identity);
  298. if (status != PEP_STATUS_OK)
  299. break;
  300. }
  301. }
  302. else if (status == PEP_CANNOT_FIND_IDENTITY) // not an error
  303. status = PEP_STATUS_OK;
  304. goto pEp_free;
  305. }
  306. else { // an identity was specified.
  307. if (is_me(session, ident)) {
  308. // FIXME: make sure this IS our fpr?
  309. // If it got sent in with an empty fpr...
  310. if (EMPTYSTR(fpr_copy)) {
  311. //
  312. // if (!EMPTYSTR(ident->fpr))
  313. // fpr_copy = strdup(ident->fpr);
  314. status = _myself(session, ident, false, true, true);
  315. if (status == PEP_STATUS_OK && ident->fpr)
  316. fpr_copy = strdup(ident->fpr);
  317. else {
  318. // last resort?
  319. // Get list of own identities
  320. char* own_id = NULL;
  321. status = get_default_own_userid(session, &own_id);
  322. if (status == PEP_STATUS_OK)
  323. status = get_user_default_key(session, own_id, &fpr_copy);
  324. if (status != PEP_STATUS_OK || EMPTYSTR(fpr_copy)) {
  325. free(own_id);
  326. return (status == PEP_STATUS_OK ? PEP_KEY_NOT_FOUND : status);
  327. }
  328. }
  329. }
  330. free(ident->fpr);
  331. ident->fpr = fpr_copy;
  332. // Create revocation
  333. status = revoke_key(session, fpr_copy, NULL);
  334. // generate new key
  335. if (status == PEP_STATUS_OK) {
  336. ident->fpr = NULL;
  337. status = generate_keypair(session, ident);
  338. }
  339. if (status == PEP_STATUS_OK) {
  340. new_key = strdup(ident->fpr);
  341. status = set_own_key(session, ident, new_key);
  342. }
  343. // mistrust fpr from trust
  344. ident->fpr = fpr_copy;
  345. ident->comm_type = PEP_ct_mistrusted;
  346. status = set_trust(session, ident);
  347. ident->fpr = NULL;
  348. // Done with old use of ident.
  349. if (status == PEP_STATUS_OK) {
  350. // Update fpr for outgoing
  351. status = myself(session, ident);
  352. }
  353. if (status == PEP_STATUS_OK)
  354. // cascade that mistrust for anyone using this key
  355. status = mark_as_compromised(session, fpr_copy);
  356. if (status == PEP_STATUS_OK)
  357. status = remove_fpr_as_default(session, fpr_copy);
  358. if (status == PEP_STATUS_OK)
  359. status = add_mistrusted_key(session, fpr_copy);
  360. // add to revocation list
  361. if (status == PEP_STATUS_OK)
  362. status = set_revoked(session, fpr_copy, new_key, time(NULL));
  363. // for all active communication partners:
  364. // active_send revocation
  365. if (status == PEP_STATUS_OK)
  366. status = send_key_reset_to_recents(session, fpr_copy, new_key);
  367. }
  368. else { // not is_me
  369. // TODO: Decide what this means. We have a non-own identity, we don't
  370. // have an fpr. Do we reset all keys for that identity?
  371. if (EMPTYSTR(fpr_copy)) {
  372. NOT_IMPLEMENTED
  373. }
  374. // remove fpr from all identities
  375. // remove fpr from all users
  376. if (status == PEP_STATUS_OK)
  377. status = remove_fpr_as_default(session, fpr_copy);
  378. // delete key from DB
  379. if (status == PEP_STATUS_OK) {
  380. status = remove_key(session, fpr_copy);
  381. };
  382. }
  383. }
  384. pEp_free:
  385. free(fpr_copy);
  386. free(own_id);
  387. free_identity_list(key_idents);
  388. free_stringlist(keys);
  389. free(new_key);
  390. return status;
  391. }