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