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.

317 lines
8.9 KiB

6 years ago
6 years ago
6 years ago
3 years ago
6 years ago
6 years ago
3 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
4 years ago
4 years ago
4 years ago
4 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. /**
  2. * @file baseprotocol.c
  3. * @brief Implementation of basic functions for administrative pEp messages (preparation,
  4. * decoration, payload, extraction, etc.). These are used for
  5. * protocol messages in, for example, key sync and key reset.
  6. * The payloads of these messages are, in general, not human-readable.
  7. * @see baseprotocol.h
  8. * @license GNU General Public License 3.0 - see LICENSE.txt
  9. */
  10. #include "pEp_internal.h"
  11. #include "message_api.h"
  12. #include "baseprotocol.h"
  13. static PEP_STATUS _get_base_protocol_type_str(base_protocol_type type, const char** type_str) {
  14. *type_str = NULL;
  15. switch(type) {
  16. case BASE_SIGN:
  17. *type_str = _BASE_PROTO_MIME_TYPE_SIGN;
  18. break;
  19. case BASE_SYNC:
  20. *type_str = _BASE_PROTO_MIME_TYPE_SYNC;
  21. break;
  22. case BASE_DISTRIBUTION:
  23. *type_str = _BASE_PROTO_MIME_TYPE_DIST;
  24. break;
  25. default:
  26. return PEP_ILLEGAL_VALUE;
  27. }
  28. return PEP_STATUS_OK;
  29. }
  30. PEP_STATUS base_decorate_message(
  31. PEP_SESSION session,
  32. message *msg,
  33. base_protocol_type type,
  34. char *payload,
  35. size_t size,
  36. const char *fpr
  37. )
  38. {
  39. PEP_STATUS status = PEP_STATUS_OK;
  40. assert(msg);
  41. assert(payload);
  42. assert(size);
  43. assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
  44. if (!(msg && payload && size && type))
  45. return PEP_ILLEGAL_VALUE;
  46. bloblist_t *bl;
  47. const char* type_str = NULL;
  48. switch (type) {
  49. case BASE_SYNC:
  50. bl = bloblist_add(msg->attachments, payload, size,
  51. _BASE_PROTO_MIME_TYPE_SYNC, "sync.pEp");
  52. break;
  53. case BASE_DISTRIBUTION:
  54. bl = bloblist_add(msg->attachments, payload, size,
  55. _BASE_PROTO_MIME_TYPE_DIST, "distribution.pEp");
  56. break;
  57. default:
  58. status = _get_base_protocol_type_str(type, &type_str);
  59. if (status != PEP_STATUS_OK)
  60. return status;
  61. else if (!type_str)
  62. return PEP_UNKNOWN_ERROR;
  63. bl = bloblist_add(msg->attachments, payload, size,
  64. type_str, "ignore_this_attachment.pEp");
  65. type_str = NULL;
  66. }
  67. if (bl == NULL)
  68. goto enomem;
  69. else if (!msg->attachments)
  70. msg->attachments = bl;
  71. if (fpr && fpr[0] != '\0') {
  72. char *sign;
  73. size_t sign_size;
  74. status = sign_only(session, payload, size, fpr, &sign, &sign_size);
  75. if (status)
  76. goto error;
  77. assert(sign && sign_size);
  78. bl = bloblist_add(bl, sign, sign_size,
  79. _BASE_PROTO_MIME_TYPE_SIGN, "electronic_signature.asc");
  80. if (!bl)
  81. goto enomem;
  82. }
  83. return status;
  84. enomem:
  85. status = PEP_OUT_OF_MEMORY;
  86. error:
  87. return status;
  88. }
  89. PEP_STATUS base_prepare_message(
  90. PEP_SESSION session,
  91. const pEp_identity *me,
  92. const pEp_identity *partner,
  93. base_protocol_type type,
  94. char *payload,
  95. size_t size,
  96. const char *fpr,
  97. message **result
  98. )
  99. {
  100. PEP_STATUS status = PEP_STATUS_OK;
  101. assert(me);
  102. assert(partner);
  103. assert(payload);
  104. assert(size);
  105. assert(result);
  106. assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
  107. if (!(me && partner && payload && size && result && type))
  108. return PEP_ILLEGAL_VALUE;
  109. *result = NULL;
  110. message *msg = new_message(PEP_dir_outgoing);
  111. if (!msg)
  112. goto enomem;
  113. add_opt_field(msg, "pEp-auto-consume", "yes");
  114. msg->in_reply_to = stringlist_add(msg->in_reply_to, "pEp-auto-consume@pEp.foundation");
  115. msg->from = identity_dup(me);
  116. if (!msg->from)
  117. goto enomem;
  118. msg->to = new_identity_list(identity_dup(partner));
  119. if (!msg->to)
  120. goto enomem;
  121. msg->shortmsg = strdup("p≡p key management message - please ignore");
  122. assert(msg->shortmsg);
  123. if (!msg->shortmsg)
  124. goto enomem;
  125. msg->longmsg = strdup("This message is part of p≡p's concept to manage keys.\n\n"
  126. "You can safely ignore it. It will be deleted automatically.\n");
  127. assert(msg->longmsg);
  128. if (!msg->longmsg)
  129. goto enomem;
  130. status = base_decorate_message(session, msg, type, payload, size, fpr);
  131. if (status == PEP_STATUS_OK)
  132. *result = msg;
  133. return status;
  134. enomem:
  135. free_message(msg);
  136. return PEP_OUT_OF_MEMORY;
  137. }
  138. PEP_STATUS base_extract_message(
  139. PEP_SESSION session,
  140. message *msg,
  141. base_protocol_type type,
  142. size_t *size,
  143. const char **payload,
  144. char **fpr
  145. )
  146. {
  147. PEP_STATUS status = PEP_STATUS_OK;
  148. assert(session && msg && size && payload && fpr);
  149. assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
  150. if (!(session && msg && size && payload && fpr && type))
  151. return PEP_ILLEGAL_VALUE;
  152. *size = 0;
  153. *payload = NULL;
  154. *fpr = NULL;
  155. const char *_payload = NULL;
  156. size_t _payload_size = 0;
  157. const char *_sign = NULL;
  158. size_t _sign_size = 0;
  159. stringlist_t *keylist = NULL;
  160. const char* type_str = NULL;
  161. status = _get_base_protocol_type_str(type, &type_str);
  162. if (status != PEP_STATUS_OK || !type_str)
  163. return status;
  164. for (bloblist_t *bl = msg->attachments; bl ; bl = bl->next) {
  165. if (bl->mime_type && strcasecmp(bl->mime_type, type_str) == 0) {
  166. if (!_payload) {
  167. _payload = bl->value;
  168. _payload_size = bl->size;
  169. }
  170. else {
  171. status = PEP_DECRYPT_WRONG_FORMAT;
  172. goto the_end;
  173. }
  174. }
  175. else if (bl->mime_type && strcasecmp(bl->mime_type, _BASE_PROTO_MIME_TYPE_SIGN) == 0) {
  176. if (!_sign) {
  177. _sign = bl->value;
  178. _sign_size = bl->size;
  179. }
  180. else {
  181. status = PEP_DECRYPT_WRONG_FORMAT;
  182. goto the_end;
  183. }
  184. }
  185. }
  186. if (!(_payload && _payload_size))
  187. goto the_end;
  188. char *_fpr = NULL;
  189. if (_sign) {
  190. status = verify_text(session, _payload, _payload_size, _sign, _sign_size, &keylist);
  191. if (!(status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED) || !keylist || !keylist->value) {
  192. // signature invalid or does not match; ignore message
  193. status = PEP_STATUS_OK;
  194. goto the_end;
  195. }
  196. _fpr = strdup(keylist->value);
  197. assert(_fpr);
  198. if (!_fpr) {
  199. status = PEP_OUT_OF_MEMORY;
  200. goto the_end;
  201. }
  202. }
  203. *size = _payload_size;
  204. *payload = _payload;
  205. *fpr = _fpr;
  206. status = PEP_STATUS_OK;
  207. the_end:
  208. free_stringlist(keylist);
  209. return status;
  210. }
  211. PEP_STATUS try_base_prepare_message(
  212. PEP_SESSION session,
  213. const pEp_identity *me,
  214. const pEp_identity *partner,
  215. base_protocol_type type,
  216. char *payload,
  217. size_t size,
  218. const char *fpr,
  219. message **result
  220. )
  221. {
  222. PEP_STATUS status = PEP_STATUS_OK;
  223. assert(session && session->messageToSend && session->notifyHandshake);
  224. assert(me);
  225. assert(partner);
  226. assert(payload);
  227. assert(size);
  228. assert(result);
  229. assert(type == BASE_SYNC || type == BASE_DISTRIBUTION);
  230. if (!(session && session->messageToSend && session->notifyHandshake))
  231. return PEP_ILLEGAL_VALUE;
  232. if (!(me && partner && payload && size && result && type))
  233. return PEP_ILLEGAL_VALUE;
  234. // https://dev.pep.foundation/Engine/MessageToSendPassphrase
  235. // first try with empty passphrase
  236. char *passphrase = session->curr_passphrase;
  237. session->curr_passphrase = NULL;
  238. status = base_prepare_message(session, me, partner, type, payload, size, fpr, result);
  239. session->curr_passphrase = passphrase;
  240. if (!(status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE))
  241. return status;
  242. if (!EMPTYSTR(session->curr_passphrase)) {
  243. // try configured passphrase
  244. status = base_prepare_message(session, me, partner, type, payload, size, fpr, result);
  245. if (!(status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE))
  246. return status;
  247. }
  248. do {
  249. // then try passphrases from the cache
  250. status = session->messageToSend(NULL);
  251. // if there will be no passphrase then exit
  252. if (status == PEP_SYNC_NO_CHANNEL)
  253. break;
  254. // if a passphrase is needed ask the app
  255. if (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE) {
  256. pEp_identity* _me = identity_dup(me);
  257. if (!_me)
  258. return PEP_OUT_OF_MEMORY;
  259. session->notifyHandshake(_me, NULL, SYNC_PASSPHRASE_REQUIRED);
  260. }
  261. else if (status == PEP_STATUS_OK) {
  262. status = base_prepare_message(session, me, partner, type, payload, size, fpr, result);
  263. }
  264. } while (status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE);
  265. return status;
  266. }