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