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.

812 lines
22 KiB

8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
7 years ago
8 years ago
6 years ago
8 years ago
8 years ago
8 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
7 years ago
7 years ago
  1. #include "platform.h"
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. #include <ctype.h>
  7. #include "pEp_internal.h"
  8. #include "keymanagement.h"
  9. #ifndef EMPTYSTR
  10. #define EMPTYSTR(STR) ((STR) == NULL || (STR)[0] == '\0')
  11. #endif
  12. #define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
  13. // Space tolerant and case insensitive fingerprint string compare
  14. static int _same_fpr(
  15. const char* fpra,
  16. size_t fpras,
  17. const char* fprb,
  18. size_t fprbs
  19. )
  20. {
  21. size_t ai = 0;
  22. size_t bi = 0;
  23. do
  24. {
  25. if(fpra[ai] == 0 || fprb[bi] == 0)
  26. {
  27. return 0;
  28. }
  29. else if(fpra[ai] == ' ')
  30. {
  31. ai++;
  32. }
  33. else if(fprb[bi] == ' ')
  34. {
  35. bi++;
  36. }
  37. else if(toupper(fpra[ai]) == toupper(fprb[bi]))
  38. {
  39. ai++;
  40. bi++;
  41. }
  42. else
  43. {
  44. return 0;
  45. }
  46. }
  47. while(ai < fpras && bi < fprbs);
  48. return ai == fpras && bi == fprbs;
  49. }
  50. PEP_STATUS elect_pubkey(
  51. PEP_SESSION session, pEp_identity * identity
  52. )
  53. {
  54. PEP_STATUS status;
  55. stringlist_t *keylist;
  56. char *_fpr = NULL;
  57. identity->comm_type = PEP_ct_unknown;
  58. status = find_keys(session, identity->address, &keylist);
  59. assert(status != PEP_OUT_OF_MEMORY);
  60. if (status == PEP_OUT_OF_MEMORY)
  61. return PEP_OUT_OF_MEMORY;
  62. stringlist_t *_keylist;
  63. for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
  64. PEP_comm_type _comm_type_key;
  65. status = get_key_rating(session, _keylist->value, &_comm_type_key);
  66. assert(status != PEP_OUT_OF_MEMORY);
  67. if (status == PEP_OUT_OF_MEMORY) {
  68. free_stringlist(keylist);
  69. return PEP_OUT_OF_MEMORY;
  70. }
  71. if (_comm_type_key != PEP_ct_compromized &&
  72. _comm_type_key != PEP_ct_unknown)
  73. {
  74. if (identity->comm_type == PEP_ct_unknown ||
  75. _comm_type_key > identity->comm_type)
  76. {
  77. identity->comm_type = _comm_type_key;
  78. _fpr = _keylist->value;
  79. }
  80. }
  81. }
  82. if (_fpr) {
  83. free(identity->fpr);
  84. identity->fpr = strdup(_fpr);
  85. if (identity->fpr == NULL) {
  86. free_stringlist(keylist);
  87. return PEP_OUT_OF_MEMORY;
  88. }
  89. }
  90. free_stringlist(keylist);
  91. return PEP_STATUS_OK;
  92. }
  93. DYNAMIC_API PEP_STATUS update_identity(
  94. PEP_SESSION session, pEp_identity * identity
  95. )
  96. {
  97. pEp_identity *stored_identity;
  98. PEP_STATUS status;
  99. assert(session);
  100. assert(identity);
  101. assert(!EMPTYSTR(identity->address));
  102. if (!(session && identity && !EMPTYSTR(identity->address)))
  103. return PEP_ILLEGAL_VALUE;
  104. int _no_user_id = EMPTYSTR(identity->user_id);
  105. int _did_elect_new_key = 0;
  106. if (_no_user_id)
  107. {
  108. free(identity->user_id);
  109. identity->user_id = calloc(1, strlen(identity->address) + 6);
  110. if (!identity->user_id)
  111. {
  112. return PEP_OUT_OF_MEMORY;
  113. }
  114. snprintf(identity->user_id, strlen(identity->address) + 6,
  115. "TOFU_%s", identity->address);
  116. }
  117. status = get_identity(session,
  118. identity->address,
  119. identity->user_id,
  120. &stored_identity);
  121. assert(status != PEP_OUT_OF_MEMORY);
  122. if (status == PEP_OUT_OF_MEMORY)
  123. goto exit_free;
  124. /* We elect a pubkey first in case there's no acceptable stored fpr */
  125. pEp_identity* temp_id = identity_dup(identity);
  126. status = elect_pubkey(session, temp_id);
  127. if (status != PEP_STATUS_OK)
  128. goto exit_free;
  129. if (stored_identity) {
  130. PEP_comm_type _comm_type_key;
  131. bool dont_use_fpr = true;
  132. /* if we have a stored_identity fpr */
  133. if (!EMPTYSTR(stored_identity->fpr)) {
  134. status = blacklist_is_listed(session, stored_identity->fpr, &dont_use_fpr);
  135. if (status != PEP_STATUS_OK)
  136. dont_use_fpr = true;
  137. }
  138. if (!dont_use_fpr) {
  139. free(temp_id->fpr);
  140. temp_id->fpr = strdup(stored_identity->fpr);
  141. assert(temp_id->fpr);
  142. if (temp_id->fpr == NULL) {
  143. status = PEP_OUT_OF_MEMORY;
  144. goto exit_free;
  145. }
  146. }
  147. else if (!EMPTYSTR(temp_id->fpr)) {
  148. status = blacklist_is_listed(session, temp_id->fpr, &dont_use_fpr);
  149. if (dont_use_fpr) {
  150. free(temp_id->fpr);
  151. temp_id->fpr = strdup("");
  152. }
  153. else {
  154. _did_elect_new_key = 1;
  155. }
  156. }
  157. else {
  158. if (temp_id->fpr == NULL)
  159. temp_id->fpr = strdup("");
  160. }
  161. /* ok, from here on out, use temp_id */
  162. /* At this point, we either have a non-blacklisted fpr we can work */
  163. /* with, or we've got nada. */
  164. if (!EMPTYSTR(temp_id->fpr)) {
  165. status = get_key_rating(session, temp_id->fpr, &_comm_type_key);
  166. assert(status != PEP_OUT_OF_MEMORY);
  167. if (status == PEP_OUT_OF_MEMORY)
  168. goto exit_free;
  169. status = get_trust(session, temp_id);
  170. if (status == PEP_OUT_OF_MEMORY)
  171. goto exit_free;
  172. if (_comm_type_key < PEP_ct_unconfirmed_encryption) {
  173. temp_id->comm_type = _comm_type_key;
  174. } else{
  175. temp_id->comm_type = stored_identity->comm_type;
  176. if (temp_id->comm_type == PEP_ct_unknown) {
  177. temp_id->comm_type = _comm_type_key;
  178. }
  179. }
  180. }
  181. if (EMPTYSTR(temp_id->username)) {
  182. free(temp_id->username);
  183. temp_id->username = strdup(stored_identity->username);
  184. assert(temp_id->username);
  185. if (temp_id->username == NULL){
  186. status = PEP_OUT_OF_MEMORY;
  187. goto exit_free;
  188. }
  189. }
  190. if (temp_id->lang[0] == 0) {
  191. temp_id->lang[0] = stored_identity->lang[0];
  192. temp_id->lang[1] = stored_identity->lang[1];
  193. temp_id->lang[2] = 0;
  194. }
  195. temp_id->flags = stored_identity->flags;
  196. }
  197. else /* stored_identity == NULL */ {
  198. temp_id->flags = 0;
  199. /* Work with the elected key from above */
  200. if (!EMPTYSTR(temp_id->fpr)) {
  201. bool dont_use_fpr = true;
  202. status = blacklist_is_listed(session, temp_id->fpr, &dont_use_fpr);
  203. if (status != PEP_STATUS_OK)
  204. dont_use_fpr = true;
  205. if (!dont_use_fpr) {
  206. PEP_comm_type _comm_type_key;
  207. status = get_key_rating(session, temp_id->fpr, &_comm_type_key);
  208. assert(status != PEP_OUT_OF_MEMORY);
  209. if (status == PEP_OUT_OF_MEMORY)
  210. goto exit_free;
  211. temp_id->comm_type = _comm_type_key;
  212. }
  213. else {
  214. free(temp_id->fpr);
  215. temp_id->fpr = strdup("");
  216. }
  217. }
  218. }
  219. if (temp_id->fpr == NULL)
  220. temp_id->fpr = strdup("");
  221. status = PEP_STATUS_OK;
  222. if (temp_id->comm_type != PEP_ct_unknown && !EMPTYSTR(temp_id->user_id)) {
  223. assert(!EMPTYSTR(temp_id->username)); // this should not happen
  224. if (EMPTYSTR(temp_id->username)) { // mitigate
  225. free(temp_id->username);
  226. temp_id->username = strdup("anonymous");
  227. assert(temp_id->username);
  228. if (temp_id->username == NULL){
  229. status = PEP_OUT_OF_MEMORY;
  230. goto exit_free;
  231. }
  232. }
  233. // Identity doesn't get stored if call was just about checking existing
  234. // user by address (i.e. no user id given but already stored)
  235. if (!(_no_user_id && stored_identity) || _did_elect_new_key)
  236. {
  237. status = set_identity(session, temp_id);
  238. assert(status == PEP_STATUS_OK);
  239. if (status != PEP_STATUS_OK) {
  240. goto exit_free;
  241. }
  242. }
  243. }
  244. if (temp_id->comm_type != PEP_ct_compromized &&
  245. temp_id->comm_type < PEP_ct_strong_but_unconfirmed)
  246. if (session->examine_identity)
  247. session->examine_identity(temp_id, session->examine_management);
  248. /* ok, we got to the end. So we can assign the output identity */
  249. free(identity->address);
  250. identity->address = strdup(temp_id->address);
  251. free(identity->fpr);
  252. identity->fpr = strdup(temp_id->fpr);
  253. free(identity->user_id);
  254. identity->user_id = strdup(temp_id->user_id);
  255. free(identity->username);
  256. identity->username = strdup(temp_id->username);
  257. identity->comm_type = temp_id->comm_type;
  258. identity->lang[0] = temp_id->lang[0];
  259. identity->lang[1] = temp_id->lang[1];
  260. identity->lang[2] = 0;
  261. identity->me = temp_id->me;
  262. identity->flags = temp_id->flags;
  263. exit_free :
  264. if (stored_identity){
  265. free_identity(stored_identity);
  266. }
  267. if (temp_id)
  268. free_identity(temp_id);
  269. return status;
  270. }
  271. PEP_STATUS elect_ownkey(
  272. PEP_SESSION session, pEp_identity * identity
  273. )
  274. {
  275. PEP_STATUS status;
  276. stringlist_t *keylist = NULL;
  277. free(identity->fpr);
  278. identity->fpr = NULL;
  279. status = find_keys(session, identity->address, &keylist);
  280. assert(status != PEP_OUT_OF_MEMORY);
  281. if (status == PEP_OUT_OF_MEMORY)
  282. return PEP_OUT_OF_MEMORY;
  283. if (keylist != NULL && keylist->value != NULL)
  284. {
  285. char *_fpr = NULL;
  286. identity->comm_type = PEP_ct_unknown;
  287. stringlist_t *_keylist;
  288. for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
  289. bool is_own = false;
  290. if (session->use_only_own_private_keys)
  291. {
  292. status = own_key_is_listed(session, _keylist->value, &is_own);
  293. assert(status == PEP_STATUS_OK);
  294. if (status != PEP_STATUS_OK) {
  295. free_stringlist(keylist);
  296. return status;
  297. }
  298. }
  299. // TODO : also accept synchronized device group keys ?
  300. if (!session->use_only_own_private_keys || is_own)
  301. {
  302. PEP_comm_type _comm_type_key;
  303. status = get_key_rating(session, _keylist->value, &_comm_type_key);
  304. assert(status != PEP_OUT_OF_MEMORY);
  305. if (status == PEP_OUT_OF_MEMORY) {
  306. free_stringlist(keylist);
  307. return PEP_OUT_OF_MEMORY;
  308. }
  309. if (_comm_type_key != PEP_ct_compromized &&
  310. _comm_type_key != PEP_ct_unknown)
  311. {
  312. if (identity->comm_type == PEP_ct_unknown ||
  313. _comm_type_key > identity->comm_type)
  314. {
  315. identity->comm_type = _comm_type_key;
  316. _fpr = _keylist->value;
  317. }
  318. }
  319. }
  320. }
  321. if (_fpr)
  322. {
  323. identity->fpr = strdup(_fpr);
  324. assert(identity->fpr);
  325. if (identity->fpr == NULL)
  326. {
  327. free_stringlist(keylist);
  328. return PEP_OUT_OF_MEMORY;
  329. }
  330. }
  331. free_stringlist(keylist);
  332. }
  333. return PEP_STATUS_OK;
  334. }
  335. DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
  336. {
  337. pEp_identity *stored_identity;
  338. PEP_STATUS status;
  339. assert(session);
  340. assert(identity);
  341. assert(identity->address);
  342. assert(identity->username);
  343. assert(EMPTYSTR(identity->user_id) ||
  344. strcmp(identity->user_id, PEP_OWN_USERID) == 0);
  345. if (!(session && identity && identity->address && identity->username &&
  346. (EMPTYSTR(identity->user_id) ||
  347. strcmp(identity->user_id, PEP_OWN_USERID) == 0)))
  348. return PEP_ILLEGAL_VALUE;
  349. identity->comm_type = PEP_ct_pEp;
  350. identity->me = true;
  351. if(EMPTYSTR(identity->user_id))
  352. {
  353. free(identity->user_id);
  354. identity->user_id = strdup(PEP_OWN_USERID);
  355. assert(identity->user_id);
  356. if (identity->user_id == NULL)
  357. {
  358. return PEP_OUT_OF_MEMORY;
  359. }
  360. }
  361. DEBUG_LOG("myself", "debug", identity->address);
  362. status = get_identity(session,
  363. identity->address,
  364. identity->user_id,
  365. &stored_identity);
  366. assert(status != PEP_OUT_OF_MEMORY);
  367. if (status == PEP_OUT_OF_MEMORY)
  368. return PEP_OUT_OF_MEMORY;
  369. if (stored_identity)
  370. {
  371. if (EMPTYSTR(identity->fpr)) {
  372. identity->fpr = strdup(stored_identity->fpr);
  373. assert(identity->fpr);
  374. if (identity->fpr == NULL)
  375. {
  376. return PEP_OUT_OF_MEMORY;
  377. }
  378. }
  379. identity->flags = stored_identity->flags;
  380. }
  381. else if (!EMPTYSTR(identity->fpr))
  382. {
  383. // App must have a good reason to give fpr, such as explicit
  384. // import of private key, or similar.
  385. // Take given fpr as-is.
  386. identity->flags = 0;
  387. }
  388. else
  389. {
  390. status = elect_ownkey(session, identity);
  391. assert(status == PEP_STATUS_OK);
  392. if (status != PEP_STATUS_OK) {
  393. return status;
  394. }
  395. identity->flags = 0;
  396. }
  397. bool revoked = false;
  398. char *r_fpr = NULL;
  399. if (!EMPTYSTR(identity->fpr))
  400. {
  401. status = key_revoked(session, identity->fpr, &revoked);
  402. // Forces re-election if key is missing and own-key-only not forced
  403. if (!session->use_only_own_private_keys && status == PEP_KEY_NOT_FOUND)
  404. {
  405. status = elect_ownkey(session, identity);
  406. assert(status == PEP_STATUS_OK);
  407. if (status != PEP_STATUS_OK) {
  408. return status;
  409. }
  410. }
  411. else if (status != PEP_STATUS_OK)
  412. {
  413. return status;
  414. }
  415. }
  416. if (EMPTYSTR(identity->fpr) || revoked)
  417. {
  418. if(revoked)
  419. {
  420. r_fpr = identity->fpr;
  421. identity->fpr = NULL;
  422. }
  423. DEBUG_LOG("generating key pair", "debug", identity->address);
  424. status = generate_keypair(session, identity);
  425. assert(status != PEP_OUT_OF_MEMORY);
  426. if (status != PEP_STATUS_OK) {
  427. char buf[11];
  428. snprintf(buf, 11, "%d", status);
  429. DEBUG_LOG("generating key pair failed", "debug", buf);
  430. if(revoked && r_fpr)
  431. free(r_fpr);
  432. return status;
  433. }
  434. if(revoked)
  435. {
  436. status = set_revoked(session, r_fpr,
  437. identity->fpr, time(NULL));
  438. free(r_fpr);
  439. if (status != PEP_STATUS_OK) {
  440. return status;
  441. }
  442. }
  443. }
  444. else
  445. {
  446. bool expired;
  447. status = key_expired(session, identity->fpr,
  448. time(NULL) + (7*24*3600), // In a week
  449. &expired);
  450. assert(status == PEP_STATUS_OK);
  451. if (status != PEP_STATUS_OK) {
  452. return status;
  453. }
  454. if (status == PEP_STATUS_OK && expired) {
  455. timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
  456. renew_key(session, identity->fpr, ts);
  457. free_timestamp(ts);
  458. }
  459. }
  460. status = set_identity(session, identity);
  461. assert(status == PEP_STATUS_OK);
  462. if (status != PEP_STATUS_OK) {
  463. return status;
  464. }
  465. return PEP_STATUS_OK;
  466. }
  467. DYNAMIC_API PEP_STATUS register_examine_function(
  468. PEP_SESSION session,
  469. examine_identity_t examine_identity,
  470. void *management
  471. )
  472. {
  473. assert(session);
  474. if (!session)
  475. return PEP_ILLEGAL_VALUE;
  476. session->examine_management = management;
  477. session->examine_identity = examine_identity;
  478. return PEP_STATUS_OK;
  479. }
  480. DYNAMIC_API PEP_STATUS do_keymanagement(
  481. retrieve_next_identity_t retrieve_next_identity,
  482. void *management
  483. )
  484. {
  485. PEP_SESSION session;
  486. pEp_identity *identity;
  487. PEP_STATUS status;
  488. assert(retrieve_next_identity);
  489. assert(management);
  490. if (!retrieve_next_identity || !management)
  491. return PEP_ILLEGAL_VALUE;
  492. status = init(&session);
  493. assert(status == PEP_STATUS_OK);
  494. if (status != PEP_STATUS_OK)
  495. return status;
  496. log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
  497. while ((identity = retrieve_next_identity(management)))
  498. {
  499. assert(identity->address);
  500. if(identity->address)
  501. {
  502. DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
  503. if (identity->me) {
  504. status = myself(session, identity);
  505. } else {
  506. status = recv_key(session, identity->address);
  507. }
  508. assert(status != PEP_OUT_OF_MEMORY);
  509. if(status == PEP_OUT_OF_MEMORY)
  510. return PEP_OUT_OF_MEMORY;
  511. }
  512. free_identity(identity);
  513. }
  514. log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
  515. release(session);
  516. return PEP_STATUS_OK;
  517. }
  518. DYNAMIC_API PEP_STATUS key_compromized(
  519. PEP_SESSION session,
  520. pEp_identity *ident
  521. )
  522. {
  523. PEP_STATUS status = PEP_STATUS_OK;
  524. assert(session);
  525. assert(ident);
  526. assert(!EMPTYSTR(ident->fpr));
  527. if (!(session && ident && ident->fpr))
  528. return PEP_ILLEGAL_VALUE;
  529. if (ident->me)
  530. {
  531. revoke_key(session, ident->fpr, NULL);
  532. myself(session, ident);
  533. }
  534. else
  535. {
  536. status = mark_as_compromized(session, ident->fpr);
  537. }
  538. return status;
  539. }
  540. DYNAMIC_API PEP_STATUS key_reset_trust(
  541. PEP_SESSION session,
  542. pEp_identity *ident
  543. )
  544. {
  545. PEP_STATUS status = PEP_STATUS_OK;
  546. assert(session);
  547. assert(ident);
  548. assert(!ident->me);
  549. assert(!EMPTYSTR(ident->fpr));
  550. assert(!EMPTYSTR(ident->address));
  551. assert(!EMPTYSTR(ident->user_id));
  552. if (!(session && ident && !ident->me && ident->fpr && ident->address &&
  553. ident->user_id))
  554. return PEP_ILLEGAL_VALUE;
  555. status = update_identity(session, ident);
  556. if (status != PEP_STATUS_OK)
  557. return status;
  558. if (ident->comm_type == PEP_ct_mistrusted)
  559. ident->comm_type = PEP_ct_unknown;
  560. else
  561. ident->comm_type &= ~PEP_ct_confirmed;
  562. status = set_identity(session, ident);
  563. if (status != PEP_STATUS_OK)
  564. return status;
  565. if (ident->comm_type == PEP_ct_unknown)
  566. status = update_identity(session, ident);
  567. return status;
  568. }
  569. DYNAMIC_API PEP_STATUS trust_personal_key(
  570. PEP_SESSION session,
  571. pEp_identity *ident
  572. )
  573. {
  574. PEP_STATUS status = PEP_STATUS_OK;
  575. assert(session);
  576. assert(ident);
  577. assert(!EMPTYSTR(ident->address));
  578. assert(!EMPTYSTR(ident->user_id));
  579. assert(!EMPTYSTR(ident->fpr));
  580. assert(!ident->me);
  581. if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  582. EMPTYSTR(ident->fpr) || ident->me)
  583. return PEP_ILLEGAL_VALUE;
  584. status = update_identity(session, ident);
  585. if (status != PEP_STATUS_OK)
  586. return status;
  587. if (ident->comm_type > PEP_ct_strong_but_unconfirmed) {
  588. ident->comm_type |= PEP_ct_confirmed;
  589. status = set_identity(session, ident);
  590. }
  591. else {
  592. // MISSING: S/MIME has to be handled depending on trusted CAs
  593. status = PEP_CANNOT_SET_TRUST;
  594. }
  595. return status;
  596. }
  597. DYNAMIC_API PEP_STATUS own_key_is_listed(
  598. PEP_SESSION session,
  599. const char *fpr,
  600. bool *listed
  601. )
  602. {
  603. PEP_STATUS status = PEP_STATUS_OK;
  604. int count;
  605. assert(session && fpr && fpr[0] && listed);
  606. if (!(session && fpr && fpr[0] && listed))
  607. return PEP_ILLEGAL_VALUE;
  608. *listed = false;
  609. sqlite3_reset(session->own_key_is_listed);
  610. sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
  611. int result;
  612. result = sqlite3_step(session->own_key_is_listed);
  613. switch (result) {
  614. case SQLITE_ROW:
  615. count = sqlite3_column_int(session->own_key_is_listed, 0);
  616. *listed = count > 0;
  617. status = PEP_STATUS_OK;
  618. break;
  619. default:
  620. status = PEP_UNKNOWN_ERROR;
  621. }
  622. sqlite3_reset(session->own_key_is_listed);
  623. return status;
  624. }
  625. DYNAMIC_API PEP_STATUS own_key_retrieve(
  626. PEP_SESSION session,
  627. stringlist_t **own_key
  628. )
  629. {
  630. PEP_STATUS status = PEP_STATUS_OK;
  631. assert(session);
  632. assert(own_key);
  633. if (!(session && own_key))
  634. return PEP_ILLEGAL_VALUE;
  635. *own_key = NULL;
  636. stringlist_t *_own_key = new_stringlist(NULL);
  637. if (_own_key == NULL)
  638. goto enomem;
  639. sqlite3_reset(session->own_key_retrieve);
  640. int result;
  641. const char *fpr = NULL;
  642. stringlist_t *_bl = _own_key;
  643. do {
  644. result = sqlite3_step(session->own_key_retrieve);
  645. switch (result) {
  646. case SQLITE_ROW:
  647. fpr = (const char *) sqlite3_column_text(session->own_key_retrieve, 0);
  648. _bl = stringlist_add(_bl, fpr);
  649. if (_bl == NULL)
  650. goto enomem;
  651. break;
  652. case SQLITE_DONE:
  653. break;
  654. default:
  655. status = PEP_UNKNOWN_ERROR;
  656. result = SQLITE_DONE;
  657. }
  658. } while (result != SQLITE_DONE);
  659. sqlite3_reset(session->own_key_retrieve);
  660. if (status == PEP_STATUS_OK)
  661. *own_key = _own_key;
  662. else
  663. free_stringlist(_own_key);
  664. goto the_end;
  665. enomem:
  666. free_stringlist(_own_key);
  667. status = PEP_OUT_OF_MEMORY;
  668. the_end:
  669. return status;
  670. }