iOS: Tracking netpgp mutex (debugging) keysync
authorDirk Zimmermann <dirk@pep-project.org>
Wed, 03 Aug 2016 18:56:31 +0200
branchkeysync
changeset 9728044e36f9ac7
parent 970 b666ae3c546e
child 973 43645546de1b
iOS: Tracking netpgp mutex (debugging)
build-mac/pEpEngine.xcodeproj/project.pbxproj
src/pgp_netpgp.c
src/pgp_netpgp.m
     1.1 --- a/build-mac/pEpEngine.xcodeproj/project.pbxproj	Tue Aug 02 19:27:27 2016 +0200
     1.2 +++ b/build-mac/pEpEngine.xcodeproj/project.pbxproj	Wed Aug 03 18:56:31 2016 +0200
     1.3 @@ -117,7 +117,7 @@
     1.4  		64A8267F1B455D0800EECAF0 /* message.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A8265B1B455D0800EECAF0 /* message.c */; };
     1.5  		64A826801B455D0800EECAF0 /* mime.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A8265D1B455D0800EECAF0 /* mime.c */; };
     1.6  		64A826811B455D0800EECAF0 /* pEpEngine.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826601B455D0800EECAF0 /* pEpEngine.c */; };
     1.7 -		64A826821B455D0800EECAF0 /* pgp_netpgp.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826631B455D0800EECAF0 /* pgp_netpgp.c */; };
     1.8 +		64A826821B455D0800EECAF0 /* pgp_netpgp.m in Sources */ = {isa = PBXBuildFile; fileRef = 64A826631B455D0800EECAF0 /* pgp_netpgp.m */; };
     1.9  		64A826831B455D0800EECAF0 /* platform_unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826651B455D0800EECAF0 /* platform_unix.c */; };
    1.10  		64A826851B455D0800EECAF0 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A8266B1B455D0800EECAF0 /* sqlite3.c */; };
    1.11  		64A826861B455D0800EECAF0 /* stringlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A8266D1B455D0800EECAF0 /* stringlist.c */; };
    1.12 @@ -311,7 +311,7 @@
    1.13  		64A826601B455D0800EECAF0 /* pEpEngine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pEpEngine.c; path = ../src/pEpEngine.c; sourceTree = "<group>"; };
    1.14  		64A826611B455D0800EECAF0 /* pEpEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pEpEngine.h; path = ../src/pEpEngine.h; sourceTree = "<group>"; };
    1.15  		64A826621B455D0800EECAF0 /* pgp_netpgp_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pgp_netpgp_internal.h; path = ../src/pgp_netpgp_internal.h; sourceTree = "<group>"; };
    1.16 -		64A826631B455D0800EECAF0 /* pgp_netpgp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pgp_netpgp.c; path = ../src/pgp_netpgp.c; sourceTree = "<group>"; };
    1.17 +		64A826631B455D0800EECAF0 /* pgp_netpgp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = pgp_netpgp.m; path = ../src/pgp_netpgp.m; sourceTree = "<group>"; };
    1.18  		64A826641B455D0800EECAF0 /* pgp_netpgp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pgp_netpgp.h; path = ../src/pgp_netpgp.h; sourceTree = "<group>"; };
    1.19  		64A826651B455D0800EECAF0 /* platform_unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = platform_unix.c; path = ../src/platform_unix.c; sourceTree = "<group>"; };
    1.20  		64A826661B455D0800EECAF0 /* platform_unix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform_unix.h; path = ../src/platform_unix.h; sourceTree = "<group>"; };
    1.21 @@ -534,7 +534,7 @@
    1.22  				64A826601B455D0800EECAF0 /* pEpEngine.c */,
    1.23  				64A826611B455D0800EECAF0 /* pEpEngine.h */,
    1.24  				64A826621B455D0800EECAF0 /* pgp_netpgp_internal.h */,
    1.25 -				64A826631B455D0800EECAF0 /* pgp_netpgp.c */,
    1.26 +				64A826631B455D0800EECAF0 /* pgp_netpgp.m */,
    1.27  				64A826641B455D0800EECAF0 /* pgp_netpgp.h */,
    1.28  				64A826651B455D0800EECAF0 /* platform_unix.c */,
    1.29  				64A826661B455D0800EECAF0 /* platform_unix.h */,
    1.30 @@ -807,7 +807,7 @@
    1.31  				646C41001D510CD800C63EFF /* constr_CHOICE.c in Sources */,
    1.32  				646C41121D510CD800C63EFF /* HandshakeRequest.c in Sources */,
    1.33  				646C41471D510D2C00C63EFF /* sync_fsm.c in Sources */,
    1.34 -				64A826821B455D0800EECAF0 /* pgp_netpgp.c in Sources */,
    1.35 +				64A826821B455D0800EECAF0 /* pgp_netpgp.m in Sources */,
    1.36  				646C41101D510CD800C63EFF /* GroupKeys.c in Sources */,
    1.37  				646C40EF1D510CD800C63EFF /* asn_SEQUENCE_OF.c in Sources */,
    1.38  				64A826891B455D0800EECAF0 /* trans_auto.c in Sources */,
     2.1 --- a/src/pgp_netpgp.c	Tue Aug 02 19:27:27 2016 +0200
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,1700 +0,0 @@
     2.4 -#include "pEp_internal.h"
     2.5 -#include "pgp_netpgp.h"
     2.6 -
     2.7 -#include <limits.h>
     2.8 -
     2.9 -#include "wrappers.h"
    2.10 -
    2.11 -#include "netpgp.h"
    2.12 -#include <netpgp/config.h>
    2.13 -#include <netpgp/memory.h>
    2.14 -#include <netpgp/crypto.h>
    2.15 -#include <netpgp/netpgpsdk.h>
    2.16 -#include <netpgp/validate.h>
    2.17 -#include <netpgp/readerwriter.h>
    2.18 -
    2.19 -#include <curl/curl.h>
    2.20 -#include <pthread.h>
    2.21 -#include <regex.h>
    2.22 -
    2.23 -static netpgp_t netpgp;
    2.24 -static pthread_mutex_t netpgp_mutex;
    2.25 -
    2.26 -static PEP_STATUS init_netpgp()
    2.27 -{
    2.28 -    PEP_STATUS status = PEP_STATUS_OK;
    2.29 -    const char *home = NULL;
    2.30 -
    2.31 -    if(pthread_mutex_init(&netpgp_mutex, NULL)){
    2.32 -        return PEP_OUT_OF_MEMORY;
    2.33 -    }
    2.34 -
    2.35 -    if(pthread_mutex_lock(&netpgp_mutex)){
    2.36 -        return PEP_UNKNOWN_ERROR;
    2.37 -    }
    2.38 -
    2.39 -    if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
    2.40 -        setlocale(LC_ALL, "");
    2.41 -
    2.42 -    memset(&netpgp, 0x0, sizeof(netpgp_t));
    2.43 -
    2.44 -    // netpgp_setvar(&netpgp, "max mem alloc", "4194304");
    2.45 -    netpgp_setvar(&netpgp, "need seckey", "1");
    2.46 -    // netpgp_setvar(&netpgp, "need userid", "1");
    2.47 -
    2.48 -    // NetPGP shares home with GPG
    2.49 -    home = gpg_home();
    2.50 -    if(home){
    2.51 -        netpgp_set_homedir(&netpgp,(char*)home, NULL, 0);
    2.52 -    }else{
    2.53 -        status = PEP_INIT_NO_GPG_HOME;
    2.54 -        goto unlock_netpgp;
    2.55 -    }
    2.56 -
    2.57 -    // pair with gpg's cert-digest-algo
    2.58 -    netpgp_setvar(&netpgp, "hash", "SHA256");
    2.59 -
    2.60 -    // subset of gpg's personal-cipher-preferences
    2.61 -    // here only one cipher can be selected
    2.62 -    netpgp_setvar(&netpgp, "cipher", "CAST5");
    2.63 -
    2.64 -    if (!netpgp_init(&netpgp)) {
    2.65 -        status = PEP_INIT_NETPGP_INIT_FAILED;
    2.66 -        goto unlock_netpgp;
    2.67 -    }
    2.68 -
    2.69 -    // netpgp_set_debug("packet-parse.c");
    2.70 -
    2.71 -unlock_netpgp:
    2.72 -    pthread_mutex_unlock(&netpgp_mutex);
    2.73 -    
    2.74 -    return status;
    2.75 -}
    2.76 -
    2.77 -static void release_netpgp()
    2.78 -{
    2.79 -    if(pthread_mutex_lock(&netpgp_mutex)){
    2.80 -        return;
    2.81 -    }
    2.82 -    netpgp_end(&netpgp);
    2.83 -    memset(&netpgp, 0x0, sizeof(netpgp_t));
    2.84 -
    2.85 -    pthread_mutex_destroy(&netpgp_mutex);
    2.86 -
    2.87 -    return;
    2.88 -}
    2.89 -
    2.90 -static PEP_STATUS init_curl(
    2.91 -    pthread_mutex_t *curl_mutex,
    2.92 -    bool in_first)
    2.93 -{
    2.94 -    PEP_STATUS status = PEP_STATUS_OK;
    2.95 -
    2.96 -    if(pthread_mutex_init(curl_mutex, NULL)){
    2.97 -        return PEP_OUT_OF_MEMORY;
    2.98 -    }
    2.99 -
   2.100 -    if(pthread_mutex_lock(curl_mutex)){
   2.101 -        return PEP_UNKNOWN_ERROR;
   2.102 -    }
   2.103 -
   2.104 -    if(in_first){
   2.105 -        curl_global_init(CURL_GLOBAL_DEFAULT);
   2.106 -    }
   2.107 -
   2.108 -    pthread_mutex_unlock(curl_mutex);
   2.109 -    return status;
   2.110 -}
   2.111 -
   2.112 -static void release_curl(
   2.113 -    pthread_mutex_t *curl_mutex, 
   2.114 -    bool out_last)
   2.115 -{
   2.116 -    if(pthread_mutex_lock(curl_mutex)){
   2.117 -        return;
   2.118 -    }
   2.119 -
   2.120 -    if(out_last){
   2.121 -        curl_global_cleanup();
   2.122 -    }
   2.123 -
   2.124 -    pthread_mutex_destroy(curl_mutex);
   2.125 -
   2.126 -    return;
   2.127 -}
   2.128 -
   2.129 -static PEP_STATUS curl_get_ctx(
   2.130 -    CURL **curl)
   2.131 -{
   2.132 -    PEP_STATUS status = PEP_STATUS_OK;
   2.133 -    struct curl_slist *headers=NULL;
   2.134 -
   2.135 -    if ((*curl = curl_easy_init()) == NULL) {
   2.136 -        return PEP_OUT_OF_MEMORY;
   2.137 -    }
   2.138 -
   2.139 -    curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
   2.140 -    curl_easy_setopt(*curl, CURLOPT_MAXREDIRS, 3L);
   2.141 -
   2.142 -    headers=curl_slist_append(headers,"Pragma: no-cache");
   2.143 -    if(headers)
   2.144 -        headers=curl_slist_append(headers,"Cache-Control: no-cache");
   2.145 -
   2.146 -    if(!headers)
   2.147 -    {
   2.148 -        return PEP_OUT_OF_MEMORY;
   2.149 -    }
   2.150 -
   2.151 -    curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
   2.152 -    curl_slist_free_all(headers);
   2.153 -
   2.154 -    // TODO curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
   2.155 -    return status;
   2.156 -}
   2.157 -
   2.158 -static void curl_release_ctx(
   2.159 -    CURL **curl)
   2.160 -{
   2.161 -    if(*curl)
   2.162 -        curl_easy_cleanup(*curl);
   2.163 -
   2.164 -    *curl = NULL;
   2.165 -
   2.166 -    return;
   2.167 -}
   2.168 -
   2.169 -PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
   2.170 -{
   2.171 -    PEP_STATUS status = PEP_STATUS_OK;
   2.172 -
   2.173 -    assert(session);
   2.174 -    if(!session) return PEP_ILLEGAL_VALUE;
   2.175 -
   2.176 -    if (in_first) {
   2.177 -        if((status = init_netpgp()) != PEP_STATUS_OK)
   2.178 -        return status;
   2.179 -    }
   2.180 -
   2.181 -    if((status = init_curl(
   2.182 -                    &session->ctx.curl_mutex,
   2.183 -                    in_first) != PEP_STATUS_OK)){
   2.184 -        if(in_first) release_netpgp();
   2.185 -        return status;
   2.186 -    }
   2.187 -
   2.188 -    return PEP_STATUS_OK;
   2.189 -}
   2.190 -
   2.191 -void pgp_release(PEP_SESSION session, bool out_last)
   2.192 -{
   2.193 -    assert(session);
   2.194 -    if(!session) return;
   2.195 -
   2.196 -    if (out_last){
   2.197 -        release_netpgp();
   2.198 -    }
   2.199 -    release_curl(&session->ctx.curl_mutex, out_last);
   2.200 -}
   2.201 -
   2.202 -// return 1 if the file contains ascii-armoured text
   2.203 -static unsigned
   2.204 -_armoured(const char *buf, size_t size, const char *pattern)
   2.205 -{
   2.206 -    unsigned armoured = 0;
   2.207 -    regex_t r;
   2.208 -    regcomp(&r, pattern, REG_EXTENDED|REG_NOSUB);
   2.209 -    if (regnexec(&r, buf, size, 0, NULL, 0) == 0) {
   2.210 -        armoured = 1;
   2.211 -    }
   2.212 -    regfree(&r);
   2.213 -    return armoured;
   2.214 -}
   2.215 -
   2.216 -/* write key fingerprint hexdump as a string */
   2.217 -static unsigned
   2.218 -fpr_to_str (char **str, const uint8_t *fpr, size_t length)
   2.219 -{
   2.220 -    unsigned i;
   2.221 -    int	n;
   2.222 -    
   2.223 -    /* 4 hexes per short + null */
   2.224 -    *str = malloc((length / 2) * 4 + 1);
   2.225 -    
   2.226 -    if(*str == NULL)
   2.227 -        return 0;
   2.228 -    
   2.229 -    for (n = 0, i = 0 ; i < length; i += 2) {
   2.230 -        n += snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
   2.231 -    }
   2.232 -    
   2.233 -    return 1;
   2.234 -}
   2.235 -
   2.236 -/* write key fingerprint bytes read from hex string
   2.237 - * accept spaces and hexes */
   2.238 -static unsigned
   2.239 -str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
   2.240 -{
   2.241 -    unsigned i,j;
   2.242 -    
   2.243 -    *length = 0;
   2.244 -    
   2.245 -    while(*str && *length < PGP_FINGERPRINT_SIZE){
   2.246 -        while (*str == ' ') str++;
   2.247 -        for (j = 0; j < 2; j++) {
   2.248 -            uint8_t *byte = &fpr[*length];
   2.249 -            *byte = 0;
   2.250 -            for (i = 0; i < 2; i++) {
   2.251 -                if (i > 0)
   2.252 -                    *byte = *byte << 4;
   2.253 -                if (*str >= 'a' && *str <= 'f')
   2.254 -                    *byte += 10 + *str - 'a';
   2.255 -                else if (*str >= 'A' && *str <= 'F')
   2.256 -                    *byte += 10 + *str - 'A';
   2.257 -                else if (*str >= '0' && *str <= '9')
   2.258 -                    *byte += *str - '0';
   2.259 -                else
   2.260 -                    return 0;
   2.261 -                str++;
   2.262 -            }
   2.263 -            (*length)++;
   2.264 -        }
   2.265 -    }
   2.266 -    return 1;
   2.267 -}
   2.268 -
   2.269 -// Iterate through netpgp' reported valid signatures 
   2.270 -// fill a list of valid figerprints
   2.271 -// returns PEP_STATUS_OK if all sig reported valid
   2.272 -// error status otherwise.
   2.273 -static PEP_STATUS _validation_results(
   2.274 -        netpgp_t *netpgp,
   2.275 -        pgp_validation_t *vresult,
   2.276 -        stringlist_t **_keylist
   2.277 -    )
   2.278 -{
   2.279 -    time_t    now;
   2.280 -    time_t    t;
   2.281 -
   2.282 -    now = time(NULL);
   2.283 -    if (now < vresult->birthtime) {
   2.284 -        // signature is not valid yet
   2.285 -        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   2.286 -    }
   2.287 -    if (vresult->duration != 0 && now > vresult->birthtime + vresult->duration) {
   2.288 -        // signature has expired
   2.289 -        t = vresult->duration + vresult->birthtime;
   2.290 -        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   2.291 -    }
   2.292 -    if (vresult->validc && vresult->valid_sigs &&
   2.293 -        !vresult->invalidc && !vresult->unknownc ) {
   2.294 -        unsigned    n;
   2.295 -        stringlist_t *k;
   2.296 -        // caller responsible to free
   2.297 -        *_keylist = new_stringlist(NULL);
   2.298 -        assert(*_keylist);
   2.299 -        if (*_keylist == NULL) {
   2.300 -            return PEP_OUT_OF_MEMORY;
   2.301 -        }
   2.302 -        k = *_keylist;
   2.303 -        for (n = 0; n < vresult->validc; ++n) {
   2.304 -            unsigned from = 0;
   2.305 -            const pgp_key_t	 *signer;
   2.306 -            char *fprstr = NULL;
   2.307 -            const uint8_t *keyid = vresult->valid_sigs[n].signer_id;
   2.308 -            
   2.309 -            signer = pgp_getkeybyid(netpgp->io, netpgp->pubring,
   2.310 -                                    keyid, &from, NULL, NULL,
   2.311 -                                    0, 0); /* check neither revocation nor expiry 
   2.312 -                                              as is should be checked already */
   2.313 -            if(signer)
   2.314 -                fpr_to_str(&fprstr,
   2.315 -                           signer->pubkeyfpr.fingerprint,
   2.316 -                           signer->pubkeyfpr.length);
   2.317 -            else
   2.318 -                return PEP_VERIFY_NO_KEY;
   2.319 -            
   2.320 -            if (fprstr == NULL)
   2.321 -                return PEP_OUT_OF_MEMORY;
   2.322 -            
   2.323 -            k = stringlist_add(k, fprstr);
   2.324 -            
   2.325 -            free(fprstr);
   2.326 -            
   2.327 -            if(!k){
   2.328 -                free_stringlist(*_keylist);
   2.329 -                return PEP_OUT_OF_MEMORY;
   2.330 -            }
   2.331 -        }
   2.332 -        return PEP_STATUS_OK;
   2.333 -    }
   2.334 -    if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
   2.335 -        // No signatures found - is this memory signed?
   2.336 -        return PEP_VERIFY_NO_KEY; 
   2.337 -    } 
   2.338 -    
   2.339 -    if (vresult->invalidc) {
   2.340 -        // some invalid signatures
   2.341 -        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   2.342 -    }
   2.343 -    
   2.344 -    // only unknown sigs
   2.345 -    return PEP_DECRYPTED;
   2.346 -}
   2.347 -
   2.348 -#define _ENDL    "\\s*(\r\n|\r|\n)"
   2.349 -#define ARMOR_HEAD    "^-----BEGIN PGP MESSAGE-----"_ENDL
   2.350 -PEP_STATUS pgp_decrypt_and_verify(
   2.351 -    PEP_SESSION session, const char *ctext, size_t csize,
   2.352 -    char **ptext, size_t *psize, stringlist_t **keylist
   2.353 -    )
   2.354 -{
   2.355 -    pgp_memory_t *mem;
   2.356 -    pgp_validation_t *vresult;
   2.357 -    char *_ptext = NULL;
   2.358 -    size_t _psize = 0;
   2.359 -
   2.360 -    PEP_STATUS result;
   2.361 -    stringlist_t *_keylist = NULL;
   2.362 -
   2.363 -    assert(session);
   2.364 -    assert(ctext);
   2.365 -    assert(csize);
   2.366 -    assert(ptext);
   2.367 -    assert(psize);
   2.368 -    assert(keylist);
   2.369 -
   2.370 -    if(!session || !ctext || !csize || !ptext || !psize || !keylist) 
   2.371 -        return PEP_ILLEGAL_VALUE;
   2.372 -
   2.373 -    if(pthread_mutex_lock(&netpgp_mutex)){
   2.374 -        return PEP_UNKNOWN_ERROR;
   2.375 -    }
   2.376 -
   2.377 -    *ptext = NULL;
   2.378 -    *psize = 0;
   2.379 -    *keylist = NULL;
   2.380 -
   2.381 -    vresult = malloc(sizeof(pgp_validation_t));
   2.382 -    memset(vresult, 0x0, sizeof(pgp_validation_t));
   2.383 -
   2.384 -    mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
   2.385 -                netpgp.secring, netpgp.pubring,
   2.386 -                _armoured(ctext, csize, ARMOR_HEAD),
   2.387 -                0 /* sshkeys */,
   2.388 -                NULL, -1, NULL  /* pass fp,attempts,cb */);
   2.389 -    if (mem == NULL) {
   2.390 -        result = PEP_OUT_OF_MEMORY;
   2.391 -        goto unlock_netpgp;
   2.392 -    }
   2.393 -
   2.394 -    _psize = pgp_mem_len(mem);
   2.395 -    if (_psize){
   2.396 -        if ((_ptext = malloc(_psize + 1)) == NULL) {
   2.397 -            result = PEP_OUT_OF_MEMORY;
   2.398 -            goto free_pgp;
   2.399 -        }
   2.400 -        memcpy(_ptext, pgp_mem_data(mem), _psize);
   2.401 -        _ptext[_psize] = '\0'; // safeguard for naive users
   2.402 -        result = PEP_DECRYPTED;
   2.403 -    }else{
   2.404 -        result = PEP_DECRYPT_NO_KEY;
   2.405 -        goto free_pgp;
   2.406 -    }
   2.407 -
   2.408 -    if (result == PEP_DECRYPTED) {
   2.409 -        result = _validation_results(&netpgp, vresult, &_keylist);
   2.410 -        if (result == PEP_DECRYPTED) {
   2.411 -            //no change
   2.412 -        } else if (result == PEP_VERIFY_NO_KEY) {
   2.413 -            result = PEP_DECRYPTED;
   2.414 -        }else if (result != PEP_STATUS_OK) {
   2.415 -            goto free_ptext;
   2.416 -        }else{
   2.417 -            result = PEP_DECRYPTED_AND_VERIFIED;
   2.418 -        }
   2.419 -    }
   2.420 -
   2.421 -    if (result == PEP_DECRYPTED_AND_VERIFIED
   2.422 -        || result == PEP_DECRYPTED) {
   2.423 -        *ptext = _ptext;
   2.424 -        *psize = _psize;
   2.425 -        (*ptext)[*psize] = 0; // safeguard for naive users
   2.426 -        if (result == PEP_DECRYPTED_AND_VERIFIED) {
   2.427 -            *keylist = _keylist;
   2.428 -        }
   2.429 -
   2.430 -        /* _ptext and _keylist ownership transfer, don't free */
   2.431 -        goto free_pgp;
   2.432 -    }
   2.433 -
   2.434 -free_keylist:
   2.435 -    free_stringlist(_keylist);
   2.436 -
   2.437 -free_ptext:
   2.438 -    free(_ptext);
   2.439 -
   2.440 -free_pgp:
   2.441 -    pgp_memory_free(mem);
   2.442 -    pgp_validate_result_free(vresult);
   2.443 -
   2.444 -unlock_netpgp:
   2.445 -    pthread_mutex_unlock(&netpgp_mutex);
   2.446 -
   2.447 -    return result;
   2.448 -}
   2.449 -
   2.450 -#define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"_ENDL
   2.451 -PEP_STATUS pgp_verify_text(
   2.452 -    PEP_SESSION session, const char *text, size_t size,
   2.453 -    const char *signature, size_t sig_size, stringlist_t **keylist
   2.454 -    )
   2.455 -{
   2.456 -    pgp_memory_t *signedmem;
   2.457 -    pgp_memory_t *sig;
   2.458 -    pgp_validation_t *vresult;
   2.459 -
   2.460 -    PEP_STATUS result;
   2.461 -    stringlist_t *_keylist;
   2.462 -
   2.463 -    assert(session);
   2.464 -    assert(text);
   2.465 -    assert(size);
   2.466 -    assert(signature);
   2.467 -    assert(sig_size);
   2.468 -    assert(keylist);
   2.469 -
   2.470 -    if(!session || !text || !size || !signature || !sig_size || !keylist) 
   2.471 -        return PEP_ILLEGAL_VALUE;
   2.472 -
   2.473 -    if(pthread_mutex_lock(&netpgp_mutex)){
   2.474 -        return PEP_UNKNOWN_ERROR;
   2.475 -    }
   2.476 -
   2.477 -    *keylist = NULL;
   2.478 -
   2.479 -    vresult = malloc(sizeof(pgp_validation_t));
   2.480 -    if (vresult == NULL) {
   2.481 -        result = PEP_OUT_OF_MEMORY;
   2.482 -        goto unlock_netpgp;
   2.483 -    }
   2.484 -    memset(vresult, 0x0, sizeof(pgp_validation_t));
   2.485 -
   2.486 -    signedmem = pgp_memory_new();
   2.487 -    if (signedmem == NULL) {
   2.488 -        result = PEP_OUT_OF_MEMORY;
   2.489 -        goto unlock_netpgp;
   2.490 -    }
   2.491 -    pgp_memory_add(signedmem, (const uint8_t*)text, size);
   2.492 -
   2.493 -    sig = pgp_memory_new();
   2.494 -    if (sig == NULL) {
   2.495 -        pgp_memory_free(signedmem);
   2.496 -        result = PEP_OUT_OF_MEMORY;
   2.497 -        goto unlock_netpgp;
   2.498 -    }
   2.499 -    pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
   2.500 -
   2.501 -    pgp_validate_mem_detached(netpgp.io, vresult, sig,
   2.502 -                NULL,/* output */
   2.503 -                _armoured(signature, sig_size, ARMOR_SIG_HEAD),
   2.504 -                netpgp.pubring,
   2.505 -                signedmem);
   2.506 -
   2.507 -    result = _validation_results(&netpgp, vresult, &_keylist);
   2.508 -    if (result != PEP_STATUS_OK) {
   2.509 -        goto free_pgp;
   2.510 -    }else{
   2.511 -        result = PEP_VERIFIED;
   2.512 -    }
   2.513 -
   2.514 -    if (result == PEP_VERIFIED) {
   2.515 -        /* TODO : check trust level */
   2.516 -        result = PEP_VERIFIED_AND_TRUSTED;
   2.517 -    }
   2.518 -
   2.519 -    if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
   2.520 -        *keylist = _keylist;
   2.521 -
   2.522 -        /* _keylist ownership transfer, don't free */
   2.523 -        goto free_pgp;
   2.524 -    }
   2.525 -
   2.526 -free_keylist:
   2.527 -    free_stringlist(_keylist);
   2.528 -
   2.529 -free_pgp:
   2.530 -    // free done by pgp_validate_mem_detached
   2.531 -    // pgp_memory_free(sig);
   2.532 -    // pgp_memory_free(signedmem);
   2.533 -    pgp_validate_result_free(vresult);
   2.534 -
   2.535 -unlock_netpgp:
   2.536 -    pthread_mutex_unlock(&netpgp_mutex);
   2.537 -
   2.538 -    return result;
   2.539 -}
   2.540 -
   2.541 -PEP_STATUS pgp_encrypt_and_sign(
   2.542 -    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   2.543 -    size_t psize, char **ctext, size_t *csize
   2.544 -    )
   2.545 -{
   2.546 -    pgp_key_t *signer = NULL;
   2.547 -    pgp_seckey_t *seckey = NULL;
   2.548 -    pgp_memory_t *signedmem;
   2.549 -    pgp_memory_t *cmem;
   2.550 -    const char *hashalg;
   2.551 -    pgp_keyring_t *rcpts;
   2.552 -
   2.553 -    PEP_STATUS result;
   2.554 -    const stringlist_t *_keylist;
   2.555 -
   2.556 -    assert(session);
   2.557 -    assert(keylist);
   2.558 -    assert(ptext);
   2.559 -    assert(psize);
   2.560 -    assert(ctext);
   2.561 -    assert(csize);
   2.562 -
   2.563 -    if(!session || !ptext || !psize || !ctext || !csize || !keylist) 
   2.564 -        return PEP_ILLEGAL_VALUE;
   2.565 -
   2.566 -    if(pthread_mutex_lock(&netpgp_mutex)){
   2.567 -        return PEP_UNKNOWN_ERROR;
   2.568 -    }
   2.569 -
   2.570 -    *ctext = NULL;
   2.571 -    *csize = 0;
   2.572 -
   2.573 -    if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
   2.574 -        result = PEP_OUT_OF_MEMORY;
   2.575 -        goto unlock_netpgp;
   2.576 -    }
   2.577 -    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
   2.578 -        assert(_keylist->value);
   2.579 -        
   2.580 -        const pgp_key_t *key;
   2.581 -        uint8_t fpr[PGP_FINGERPRINT_SIZE];
   2.582 -        size_t fprlen;
   2.583 -        unsigned from = 0;
   2.584 -
   2.585 -        if (str_to_fpr(_keylist->value, fpr, &fprlen)) {
   2.586 -            if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
   2.587 -                                                    fpr, fprlen, &from, NULL,
   2.588 -                                                    /* reject revoked, accept expired */
   2.589 -                                                    1,0)) == NULL) {
   2.590 -                result = PEP_KEY_NOT_FOUND;
   2.591 -                goto free_rcpts;
   2.592 -            }
   2.593 -        }else{
   2.594 -            result = PEP_ILLEGAL_VALUE;
   2.595 -            goto free_rcpts;
   2.596 -        }
   2.597 -
   2.598 -        /* Signer is the first key in the list */
   2.599 -        if(signer == NULL){
   2.600 -            from = 0;
   2.601 -            signer = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.secring,
   2.602 -                                                  fpr, fprlen,
   2.603 -                                                  &from,
   2.604 -                                                  NULL,
   2.605 -                                                  0,0); /* accept any */
   2.606 -            if(signer == NULL){
   2.607 -                result = PEP_KEY_NOT_FOUND;
   2.608 -                goto free_rcpts;
   2.609 -            }
   2.610 -        }
   2.611 -
   2.612 -        // add key to recipients/signers
   2.613 -        pgp_keyring_add(rcpts, key);
   2.614 -        if(rcpts->keys == NULL){
   2.615 -            result = PEP_OUT_OF_MEMORY;
   2.616 -            goto free_rcpts;
   2.617 -        }
   2.618 -    }
   2.619 -
   2.620 -    /* Empty keylist ?*/
   2.621 -    if(rcpts->keyc == 0){
   2.622 -        result = PEP_ILLEGAL_VALUE;
   2.623 -        goto free_rcpts;
   2.624 -    }
   2.625 -
   2.626 -    seckey = pgp_key_get_certkey(signer);
   2.627 -
   2.628 -    /* No signig key. Revoked ? */
   2.629 -    if(seckey == NULL){
   2.630 -        result = PEP_GET_KEY_FAILED;
   2.631 -        goto free_rcpts;
   2.632 -    }
   2.633 -
   2.634 -    hashalg = netpgp_getvar(&netpgp, "hash");
   2.635 -
   2.636 -    // Sign data
   2.637 -    signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
   2.638 -                time(NULL), /* birthtime */
   2.639 -                0 /* duration */,
   2.640 -                hashalg, 
   2.641 -                0 /* armored */,
   2.642 -                0 /* cleartext */);
   2.643 -
   2.644 -    if (!signedmem) {
   2.645 -        result = PEP_UNENCRYPTED;
   2.646 -        goto free_rcpts;
   2.647 -    }
   2.648 -
   2.649 -    // Encrypt signed data
   2.650 -
   2.651 -    cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
   2.652 -            pgp_mem_len(signedmem), rcpts, 1 /* armored */,
   2.653 -            netpgp_getvar(&netpgp, "cipher"), 
   2.654 -            1 /* takes raw OpenPGP message */);
   2.655 -
   2.656 -    if (cmem == NULL) {
   2.657 -        result = PEP_OUT_OF_MEMORY;
   2.658 -        goto free_signedmem;
   2.659 -    }else{
   2.660 -
   2.661 -        char *_buffer = NULL;
   2.662 -        size_t length = pgp_mem_len(cmem);
   2.663 -
   2.664 -        // Allocate transferable buffer
   2.665 -        _buffer = malloc(length + 1);
   2.666 -        assert(_buffer);
   2.667 -        if (_buffer == NULL) {
   2.668 -            result = PEP_OUT_OF_MEMORY;
   2.669 -            goto free_cmem;
   2.670 -        }
   2.671 -
   2.672 -        memcpy(_buffer, pgp_mem_data(cmem), length);
   2.673 -
   2.674 -        *ctext = _buffer;
   2.675 -        *csize = length;
   2.676 -        (*ctext)[*csize] = 0; // safeguard for naive users
   2.677 -        result = PEP_STATUS_OK;
   2.678 -    }
   2.679 -
   2.680 -free_cmem :
   2.681 -    pgp_memory_free(cmem);
   2.682 -free_signedmem :
   2.683 -    pgp_memory_free(signedmem);
   2.684 -free_rcpts :
   2.685 -    pgp_keyring_free(rcpts);
   2.686 -unlock_netpgp:
   2.687 -    pthread_mutex_unlock(&netpgp_mutex);
   2.688 -
   2.689 -    return result;
   2.690 -}
   2.691 -
   2.692 -PEP_STATUS pgp_generate_keypair(
   2.693 -    PEP_SESSION session, pEp_identity *identity
   2.694 -    )
   2.695 -{
   2.696 -    pgp_key_t	newseckey;
   2.697 -    pgp_key_t	*newpubkey;
   2.698 -
   2.699 -    PEP_STATUS result;
   2.700 -    char newid[1024];
   2.701 -    const char *hashalg;
   2.702 -    const char *cipher;
   2.703 -
   2.704 -    assert(session);
   2.705 -    assert(identity);
   2.706 -    assert(identity->address);
   2.707 -    assert(identity->fpr == NULL);
   2.708 -    assert(identity->username);
   2.709 -
   2.710 -    if(!session || !identity || 
   2.711 -       !identity->address || identity->fpr || !identity->username)
   2.712 -        return PEP_ILLEGAL_VALUE;
   2.713 -
   2.714 -    if(pthread_mutex_lock(&netpgp_mutex)){
   2.715 -        return PEP_UNKNOWN_ERROR;
   2.716 -    }
   2.717 -
   2.718 -    if(snprintf(newid, sizeof(newid),
   2.719 -        "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
   2.720 -        result =  PEP_BUFFER_TOO_SMALL;
   2.721 -        goto unlock_netpgp;
   2.722 -    }
   2.723 -    
   2.724 -    hashalg = netpgp_getvar(&netpgp, "hash");
   2.725 -    cipher = netpgp_getvar(&netpgp, "cipher");
   2.726 -
   2.727 -    bzero(&newseckey, sizeof(newseckey));
   2.728 -
   2.729 -    // Generate the key
   2.730 -    if (!pgp_rsa_generate_keypair(&newseckey, 4096, 65537UL, hashalg, cipher,
   2.731 -                                  (const uint8_t *) "", (const size_t) 0))
   2.732 -    {
   2.733 -        result = PEP_CANNOT_CREATE_KEY;
   2.734 -        goto free_seckey;
   2.735 -    }
   2.736 -
   2.737 -    /* make a public key out of generated secret key */
   2.738 -    if((newpubkey = pgp_ensure_pubkey(
   2.739 -            netpgp.pubring,
   2.740 -            &newseckey.key.seckey.pubkey,
   2.741 -            newseckey.pubkeyid))==NULL)
   2.742 -    {
   2.743 -        result = PEP_OUT_OF_MEMORY;
   2.744 -        goto free_seckey;
   2.745 -    }
   2.746 -
   2.747 -    // "Expire-Date: 1y\n";
   2.748 -    if (!pgp_add_selfsigned_userid(&newseckey, newpubkey, 
   2.749 -                                  (uint8_t *)newid, 365*24*3600))
   2.750 -    {
   2.751 -        result = PEP_CANNOT_CREATE_KEY;
   2.752 -        goto delete_pubkey;
   2.753 -    }
   2.754 -
   2.755 -    if (newpubkey == NULL)
   2.756 -    {
   2.757 -        result = PEP_OUT_OF_MEMORY;
   2.758 -        goto delete_pubkey;
   2.759 -    }
   2.760 -
   2.761 -    // Append key to netpgp's rings (key ownership transfered)
   2.762 -    if (!pgp_keyring_add(netpgp.secring, &newseckey)){
   2.763 -        result = PEP_OUT_OF_MEMORY;
   2.764 -        goto delete_pubkey;
   2.765 -    } 
   2.766 -
   2.767 -    // save rings 
   2.768 -    if (netpgp_save_pubring(&netpgp) && netpgp_save_secring(&netpgp))
   2.769 -    {
   2.770 -        char *fprstr = NULL;
   2.771 -        fpr_to_str(&fprstr,
   2.772 -                   newseckey.pubkeyfpr.fingerprint,
   2.773 -                   newseckey.pubkeyfpr.length);
   2.774 -
   2.775 -        if (fprstr == NULL) {
   2.776 -            result = PEP_OUT_OF_MEMORY;
   2.777 -            goto pop_secring;
   2.778 -        } 
   2.779 -
   2.780 -        /* keys saved, pass fingerprint back */
   2.781 -        identity->fpr = fprstr;
   2.782 -        result = PEP_STATUS_OK;
   2.783 -
   2.784 -        /* free nothing, everything transfered */
   2.785 -        goto unlock_netpgp;
   2.786 -    } else {
   2.787 -        /* XXX in case only pubring save succeed
   2.788 -         * pubring file is left as-is, but backup restore
   2.789 -         * could be attempted if such corner case matters */
   2.790 -        result = PEP_UNKNOWN_ERROR;
   2.791 -    }
   2.792 -
   2.793 -pop_secring:
   2.794 -    ((pgp_keyring_t *)netpgp.secring)->keyc--;
   2.795 -delete_pubkey:
   2.796 -    pgp_deletekeybyfpr(netpgp.io,
   2.797 -                    (pgp_keyring_t *)netpgp.pubring, 
   2.798 -                    newseckey.pubkeyfpr.fingerprint,
   2.799 -                    newseckey.pubkeyfpr.length);
   2.800 -free_seckey:
   2.801 -    pgp_key_free(&newseckey);
   2.802 -unlock_netpgp:
   2.803 -    pthread_mutex_unlock(&netpgp_mutex);
   2.804 -
   2.805 -    return result;
   2.806 -}
   2.807 -
   2.808 -PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
   2.809 -{
   2.810 -    uint8_t fpr[PGP_FINGERPRINT_SIZE];
   2.811 -    size_t length;
   2.812 -
   2.813 -    PEP_STATUS result;
   2.814 -
   2.815 -    assert(session);
   2.816 -    assert(fprstr);
   2.817 -
   2.818 -    if (!session || !fprstr)
   2.819 -        return PEP_ILLEGAL_VALUE;
   2.820 -
   2.821 -    if(pthread_mutex_lock(&netpgp_mutex)){
   2.822 -        return PEP_UNKNOWN_ERROR;
   2.823 -    }
   2.824 -    
   2.825 -    if (str_to_fpr(fprstr, fpr, &length)) {
   2.826 -        unsigned insec = pgp_deletekeybyfpr(netpgp.io,
   2.827 -                                (pgp_keyring_t *)netpgp.secring, 
   2.828 -                                (const uint8_t *)fpr, length);
   2.829 -        unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
   2.830 -                                (pgp_keyring_t *)netpgp.pubring, 
   2.831 -                                (const uint8_t *)fpr, length);
   2.832 -        if(!insec && !inpub){
   2.833 -            result = PEP_KEY_NOT_FOUND;
   2.834 -            goto unlock_netpgp;
   2.835 -        } else {
   2.836 -            result = PEP_STATUS_OK;
   2.837 -        }
   2.838 -    }else{
   2.839 -        result = PEP_OUT_OF_MEMORY;
   2.840 -        goto unlock_netpgp;
   2.841 -    }
   2.842 -
   2.843 -    // save rings 
   2.844 -    if (netpgp_save_pubring(&netpgp) && 
   2.845 -        netpgp_save_secring(&netpgp))
   2.846 -    {
   2.847 -        result = PEP_STATUS_OK;
   2.848 -    }else{
   2.849 -        result = PEP_UNKNOWN_ERROR;
   2.850 -    }
   2.851 -
   2.852 -unlock_netpgp:
   2.853 -    pthread_mutex_unlock(&netpgp_mutex);
   2.854 -
   2.855 -    return result;
   2.856 -}
   2.857 -
   2.858 -#define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----"_ENDL
   2.859 -PEP_STATUS pgp_import_keydata(
   2.860 -        PEP_SESSION session,
   2.861 -        const char *key_data, 
   2.862 -        size_t size
   2.863 -    )
   2.864 -{
   2.865 -    pgp_memory_t *mem;
   2.866 -
   2.867 -    PEP_STATUS result = PEP_STATUS_OK;
   2.868 -
   2.869 -    assert(session);
   2.870 -    assert(key_data);
   2.871 -
   2.872 -    if(!session || !key_data) 
   2.873 -        return PEP_ILLEGAL_VALUE;
   2.874 -
   2.875 -    if(pthread_mutex_lock(&netpgp_mutex)){
   2.876 -        return PEP_UNKNOWN_ERROR;
   2.877 -    }
   2.878 -
   2.879 -    mem = pgp_memory_new();
   2.880 -    if (mem == NULL) {
   2.881 -        result = PEP_OUT_OF_MEMORY;
   2.882 -        goto unlock_netpgp;
   2.883 -    }
   2.884 -    pgp_memory_add(mem, (const uint8_t*)key_data, size);
   2.885 -
   2.886 -    if (pgp_keyring_read_from_mem(netpgp.io, netpgp.pubring, netpgp.secring, 
   2.887 -                                  _armoured(key_data, size, ARMOR_KEY_HEAD),
   2.888 -                                  mem) == 0){
   2.889 -        result = PEP_ILLEGAL_VALUE;
   2.890 -    }    
   2.891 -
   2.892 -    pgp_memory_free(mem);
   2.893 -
   2.894 -    // save rings 
   2.895 -    if (netpgp_save_pubring(&netpgp) && 
   2.896 -        netpgp_save_secring(&netpgp))
   2.897 -    {
   2.898 -        result = PEP_STATUS_OK;
   2.899 -    }else{
   2.900 -        result = PEP_UNKNOWN_ERROR;
   2.901 -    }
   2.902 -
   2.903 -unlock_netpgp:
   2.904 -    pthread_mutex_unlock(&netpgp_mutex);
   2.905 -
   2.906 -    return result;
   2.907 -}
   2.908 -
   2.909 -static PEP_STATUS _export_keydata(
   2.910 -    pgp_key_t *key,
   2.911 -    char **buffer,
   2.912 -    size_t *buflen
   2.913 -    )
   2.914 -{
   2.915 -    PEP_STATUS result;
   2.916 -	pgp_output_t *output;
   2.917 -    pgp_memory_t *mem;
   2.918 -	pgp_setup_memory_write(&output, &mem, 128);
   2.919 -
   2.920 -    if (mem == NULL || output == NULL) {
   2.921 -        return PEP_ILLEGAL_VALUE;
   2.922 -    }
   2.923 -
   2.924 -    if (!pgp_write_xfer_key(output, key, 1)) {
   2.925 -        result = PEP_UNKNOWN_ERROR;
   2.926 -        goto free_mem;
   2.927 -    }
   2.928 -
   2.929 -    *buffer = NULL;
   2.930 -    *buflen = pgp_mem_len(mem);
   2.931 -
   2.932 -    // Allocate transferable buffer
   2.933 -    *buffer = malloc(*buflen + 1);
   2.934 -    assert(*buffer);
   2.935 -    if (*buffer == NULL) {
   2.936 -        result = PEP_OUT_OF_MEMORY;
   2.937 -        goto free_mem;
   2.938 -    }
   2.939 -
   2.940 -    memcpy(*buffer, pgp_mem_data(mem), *buflen);
   2.941 -    (*buffer)[*buflen] = 0; // safeguard for naive users
   2.942 -
   2.943 -    return PEP_STATUS_OK;
   2.944 -
   2.945 -free_mem :
   2.946 -	pgp_teardown_memory_write(output, mem);
   2.947 -
   2.948 -    return result;
   2.949 -}
   2.950 -
   2.951 -PEP_STATUS pgp_export_keydata(
   2.952 -    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
   2.953 -    )
   2.954 -{
   2.955 -    pgp_key_t *key;
   2.956 -    uint8_t fpr[PGP_FINGERPRINT_SIZE];
   2.957 -    size_t fprlen;
   2.958 -
   2.959 -    PEP_STATUS result;
   2.960 -    char *buffer;
   2.961 -    size_t buflen;
   2.962 -
   2.963 -    assert(session);
   2.964 -    assert(fprstr);
   2.965 -    assert(key_data);
   2.966 -    assert(size);
   2.967 -
   2.968 -    if (!session || !fprstr || !key_data || !size)
   2.969 -        return PEP_ILLEGAL_VALUE;
   2.970 -
   2.971 -    if(pthread_mutex_lock(&netpgp_mutex)){
   2.972 -        return PEP_UNKNOWN_ERROR;
   2.973 -    }
   2.974 -
   2.975 -    if (str_to_fpr(fprstr, fpr, &fprlen)) {
   2.976 -        unsigned from = 0;
   2.977 -
   2.978 -        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
   2.979 -                                                fpr, fprlen, &from,
   2.980 -                                                NULL,0,0)) == NULL) {
   2.981 -            result = PEP_KEY_NOT_FOUND;
   2.982 -            goto unlock_netpgp;
   2.983 -        }
   2.984 -    }else{
   2.985 -        result = PEP_OUT_OF_MEMORY;
   2.986 -        goto unlock_netpgp;
   2.987 -    }
   2.988 -    
   2.989 -    result = _export_keydata(key, &buffer, &buflen);
   2.990 -    
   2.991 -    if(result == PEP_STATUS_OK)
   2.992 -    {
   2.993 -        *key_data = buffer;
   2.994 -        *size = buflen;
   2.995 -        result = PEP_STATUS_OK;
   2.996 -    }
   2.997 -
   2.998 -unlock_netpgp:
   2.999 -    pthread_mutex_unlock(&netpgp_mutex);
  2.1000 -
  2.1001 -    return result;
  2.1002 -}
  2.1003 -
  2.1004 -struct HKP_answer {
  2.1005 -  char *memory;
  2.1006 -  size_t size;
  2.1007 -};
  2.1008 - 
  2.1009 -static size_t
  2.1010 -HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
  2.1011 -{
  2.1012 -  size_t realsize = size * nmemb;
  2.1013 -  struct HKP_answer *mem = (struct HKP_answer *)userp;
  2.1014 - 
  2.1015 -  mem->memory = realloc(mem->memory, mem->size + realsize + 1);
  2.1016 -  if(mem->memory == NULL) {
  2.1017 -    mem->size = 0;
  2.1018 -    return 0;
  2.1019 -  }
  2.1020 - 
  2.1021 -  memcpy(&(mem->memory[mem->size]), contents, realsize);
  2.1022 -  mem->size += realsize;
  2.1023 -  mem->memory[mem->size] = 0;
  2.1024 - 
  2.1025 -  return realsize;
  2.1026 -}
  2.1027 -
  2.1028 -#define HKP_SERVER "http://keys.gnupg.net:11371"
  2.1029 -// #define HKP_SERVER "http://127.0.0.1:11371"
  2.1030 -
  2.1031 -PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  2.1032 -{
  2.1033 -    static const char *ks_cmd = HKP_SERVER
  2.1034 -                                "/pks/lookup?"
  2.1035 -                                "op=get&options=mr&exact=on&"
  2.1036 -                                "search=";
  2.1037 -    char *encoded_pattern;
  2.1038 -    char *request = NULL;
  2.1039 -    struct HKP_answer answer;
  2.1040 -    CURLcode curlres;
  2.1041 -       
  2.1042 -    PEP_STATUS result;
  2.1043 -
  2.1044 -    CURL *curl;
  2.1045 -
  2.1046 -    assert(session);
  2.1047 -    assert(pattern);
  2.1048 -
  2.1049 -    if (!session || !pattern )
  2.1050 -        return PEP_ILLEGAL_VALUE;
  2.1051 -
  2.1052 -    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  2.1053 -        return PEP_UNKNOWN_ERROR;
  2.1054 -    }
  2.1055 -
  2.1056 -    result = curl_get_ctx(&curl);
  2.1057 -    if(result != PEP_STATUS_OK){
  2.1058 -        goto unlock_curl;
  2.1059 -    }
  2.1060 -
  2.1061 -    encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
  2.1062 -    if(!encoded_pattern){
  2.1063 -        result = PEP_OUT_OF_MEMORY;
  2.1064 -        goto release_curl_ctx;
  2.1065 -    }
  2.1066 -
  2.1067 -    if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
  2.1068 -        result = PEP_OUT_OF_MEMORY;
  2.1069 -        goto free_encoded_pattern;
  2.1070 -    }
  2.1071 -
  2.1072 -    //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
  2.1073 -    stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
  2.1074 -
  2.1075 -    curl_easy_setopt(curl, CURLOPT_URL,request);
  2.1076 -
  2.1077 -    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
  2.1078 -
  2.1079 -    answer.memory = NULL;
  2.1080 -    answer.size = 0;
  2.1081 -    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
  2.1082 -
  2.1083 -    curlres = curl_easy_perform(curl);
  2.1084 -    if(curlres != CURLE_OK) {
  2.1085 -        result = PEP_GET_KEY_FAILED;
  2.1086 -        goto free_request;
  2.1087 -    }
  2.1088 -
  2.1089 -    if(!answer.memory || !answer.size) {
  2.1090 -        result = PEP_OUT_OF_MEMORY;
  2.1091 -        goto free_request;
  2.1092 -    }
  2.1093 -
  2.1094 -    result = pgp_import_keydata(session, 
  2.1095 -                                answer.memory, 
  2.1096 -                                answer.size);
  2.1097 -
  2.1098 -free_answer:
  2.1099 -    free(answer.memory);
  2.1100 -free_request:
  2.1101 -    free(request);
  2.1102 -free_encoded_pattern:
  2.1103 -    curl_free(encoded_pattern);
  2.1104 -release_curl_ctx:
  2.1105 -    curl_release_ctx(&curl);
  2.1106 -unlock_curl:
  2.1107 -    pthread_mutex_unlock(&session->ctx.curl_mutex);
  2.1108 -
  2.1109 -    return result;
  2.1110 -}
  2.1111 -
  2.1112 -typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
  2.1113 -
  2.1114 -static PEP_STATUS find_keys_do(
  2.1115 -        const char *pattern, find_key_cb_t cb, void* cb_arg)
  2.1116 -{
  2.1117 -    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  2.1118 -    size_t length;
  2.1119 -    pgp_key_t *key;
  2.1120 -
  2.1121 -    PEP_STATUS result;
  2.1122 -
  2.1123 -    // Try find a fingerprint in pattern
  2.1124 -    if (str_to_fpr(pattern, fpr, &length)) {
  2.1125 -        unsigned from = 0;
  2.1126 -
  2.1127 -
  2.1128 -        // Only one fingerprint can match
  2.1129 -        if ((key = (pgp_key_t *)pgp_getkeybyfpr(
  2.1130 -                        netpgp.io,
  2.1131 -                        (pgp_keyring_t *)netpgp.pubring, 
  2.1132 -                        (const uint8_t *)fpr, length,
  2.1133 -                        &from,
  2.1134 -                        NULL, 0, 0)) == NULL) {
  2.1135 -
  2.1136 -            return PEP_KEY_NOT_FOUND;
  2.1137 -        }
  2.1138 -
  2.1139 -        result = cb(cb_arg, key);
  2.1140 -
  2.1141 -    } else {
  2.1142 -        // Search by name for pattern. Can match many.
  2.1143 -        unsigned from = 0;
  2.1144 -        result = PEP_KEY_NOT_FOUND;
  2.1145 -        while((key = (pgp_key_t *)pgp_getnextkeybyname(
  2.1146 -                        netpgp.io,
  2.1147 -                        (pgp_keyring_t *)netpgp.pubring, 
  2.1148 -			            (const char *)pattern,
  2.1149 -                        &from)) != NULL) {
  2.1150 -
  2.1151 -            result = cb(cb_arg, key);
  2.1152 -            if (result != PEP_STATUS_OK)
  2.1153 -                break;
  2.1154 -
  2.1155 -            from++;
  2.1156 -        }
  2.1157 -    }
  2.1158 -
  2.1159 -    return result;
  2.1160 -}
  2.1161 -
  2.1162 -static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
  2.1163 -{
  2.1164 -    stringlist_t **keylist = arg;
  2.1165 -    char *newfprstr = NULL;
  2.1166 -
  2.1167 -    fpr_to_str(&newfprstr,
  2.1168 -               key->pubkeyfpr.fingerprint,
  2.1169 -               key->pubkeyfpr.length);
  2.1170 -
  2.1171 -    if (newfprstr == NULL) {
  2.1172 -        return PEP_OUT_OF_MEMORY;
  2.1173 -    } else { 
  2.1174 -
  2.1175 -        *keylist = stringlist_add(*keylist, newfprstr);
  2.1176 -        free(newfprstr);
  2.1177 -        if (*keylist == NULL) {
  2.1178 -            return PEP_OUT_OF_MEMORY;
  2.1179 -        }
  2.1180 -    }
  2.1181 -    return PEP_STATUS_OK;
  2.1182 -}
  2.1183 -
  2.1184 -PEP_STATUS pgp_find_keys(
  2.1185 -    PEP_SESSION session, const char *pattern, stringlist_t **keylist
  2.1186 -    )
  2.1187 -{
  2.1188 -    stringlist_t *_keylist, *_k;
  2.1189 -
  2.1190 -    PEP_STATUS result;
  2.1191 -
  2.1192 -    assert(session);
  2.1193 -    assert(pattern);
  2.1194 -    assert(keylist);
  2.1195 -
  2.1196 -    if (!session || !pattern || !keylist )
  2.1197 -    {
  2.1198 -        return PEP_ILLEGAL_VALUE;
  2.1199 -    }
  2.1200 -
  2.1201 -    if (pthread_mutex_lock(&netpgp_mutex))
  2.1202 -    {
  2.1203 -        return PEP_UNKNOWN_ERROR;
  2.1204 -    }
  2.1205 -
  2.1206 -    *keylist = NULL;
  2.1207 -    _keylist = new_stringlist(NULL);
  2.1208 -    if (_keylist == NULL) {
  2.1209 -        result = PEP_OUT_OF_MEMORY;
  2.1210 -        goto unlock_netpgp;
  2.1211 -    }
  2.1212 -    _k = _keylist;
  2.1213 -
  2.1214 -    result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  2.1215 -
  2.1216 -    if (result == PEP_STATUS_OK) {
  2.1217 -        *keylist = _keylist;
  2.1218 -        // Transfer ownership, no free
  2.1219 -        goto unlock_netpgp;
  2.1220 -    }
  2.1221 -
  2.1222 -free_keylist:
  2.1223 -    free_stringlist(_keylist);
  2.1224 -
  2.1225 -unlock_netpgp:
  2.1226 -    pthread_mutex_unlock(&netpgp_mutex);
  2.1227 -
  2.1228 -    return result;
  2.1229 -}
  2.1230 -
  2.1231 -#define HKP_REQ_PREFIX "keytext="
  2.1232 -#define HKP_REQ_PREFIX_LEN 8
  2.1233 -
  2.1234 -static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
  2.1235 -{
  2.1236 -    char *buffer = NULL;
  2.1237 -    size_t buflen = 0;
  2.1238 -    PEP_STATUS result;
  2.1239 -    stringlist_t *encoded_keys;
  2.1240 -    encoded_keys = (stringlist_t*)arg;
  2.1241 -
  2.1242 -    result = _export_keydata(key, &buffer, &buflen);
  2.1243 -    
  2.1244 -    if(result == PEP_STATUS_OK){
  2.1245 -        char *encoded_key = curl_escape(buffer, (int)buflen);
  2.1246 -        if(!encoded_key){
  2.1247 -            result = PEP_OUT_OF_MEMORY;
  2.1248 -            goto free_buffer;
  2.1249 -        }
  2.1250 -        size_t encoded_key_len = strlen(encoded_key);
  2.1251 -
  2.1252 -        char *request = calloc(1, HKP_REQ_PREFIX_LEN + encoded_key_len + 1);
  2.1253 -        if(!request){
  2.1254 -            result = PEP_OUT_OF_MEMORY;
  2.1255 -            goto free_encoded_key;
  2.1256 -        }
  2.1257 -        
  2.1258 -        memcpy(request, HKP_REQ_PREFIX, HKP_REQ_PREFIX_LEN);
  2.1259 -        memcpy(request + HKP_REQ_PREFIX_LEN, encoded_key, encoded_key_len);
  2.1260 -        request[HKP_REQ_PREFIX_LEN + encoded_key_len] = '\0';
  2.1261 -
  2.1262 -        if(!stringlist_add(encoded_keys, request)){
  2.1263 -            free(request);
  2.1264 -            result = PEP_OUT_OF_MEMORY;
  2.1265 -        }
  2.1266 -
  2.1267 -        free(request);
  2.1268 -
  2.1269 -free_encoded_key:
  2.1270 -        curl_free(encoded_key);
  2.1271 -
  2.1272 -free_buffer:        
  2.1273 -        free(buffer);
  2.1274 -    }
  2.1275 -
  2.1276 -    return result;
  2.1277 -}
  2.1278 -
  2.1279 -PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  2.1280 -{
  2.1281 -    static const char *ks_cmd = HKP_SERVER "/pks/add";
  2.1282 -
  2.1283 -    PEP_STATUS result;
  2.1284 -    CURL *curl = NULL;
  2.1285 -
  2.1286 -    assert(session);
  2.1287 -    assert(pattern);
  2.1288 -
  2.1289 -    if (!session || !pattern )
  2.1290 -        return PEP_ILLEGAL_VALUE;
  2.1291 -
  2.1292 -    stringlist_t *encoded_keys = new_stringlist(NULL);
  2.1293 -    assert(encoded_keys);
  2.1294 -    if (encoded_keys == NULL) {
  2.1295 -        return PEP_OUT_OF_MEMORY;
  2.1296 -    }
  2.1297 -
  2.1298 -    if(pthread_mutex_lock(&netpgp_mutex)){
  2.1299 -        result = PEP_UNKNOWN_ERROR;
  2.1300 -        goto free_encoded_keys;
  2.1301 -    }
  2.1302 -
  2.1303 -    result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
  2.1304 -
  2.1305 -    pthread_mutex_unlock(&netpgp_mutex);
  2.1306 -
  2.1307 -    if(result != PEP_STATUS_OK){
  2.1308 -        goto free_encoded_keys;
  2.1309 -    }
  2.1310 -
  2.1311 -    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  2.1312 -        result = PEP_UNKNOWN_ERROR;
  2.1313 -        goto free_encoded_keys;
  2.1314 -    }
  2.1315 -
  2.1316 -    result = curl_get_ctx(&curl);
  2.1317 -    if(result != PEP_STATUS_OK){
  2.1318 -        goto unlock_curl;
  2.1319 -    }
  2.1320 -
  2.1321 -    if(result == PEP_STATUS_OK){
  2.1322 -        CURLcode curlres;
  2.1323 -
  2.1324 -        for (const stringlist_t *post = encoded_keys; post != NULL; post = post->next) {
  2.1325 -            assert(post->value);
  2.1326 -
  2.1327 -            curl_easy_setopt(curl, CURLOPT_URL, ks_cmd);
  2.1328 -            curl_easy_setopt(curl, CURLOPT_POST, 1L);
  2.1329 -            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post->value);
  2.1330 -            curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
  2.1331 -
  2.1332 -            // Uncomment if debugging
  2.1333 -            // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  2.1334 -
  2.1335 -            curlres = curl_easy_perform(curl);
  2.1336 -
  2.1337 -            if(curlres != CURLE_OK) {
  2.1338 -
  2.1339 -                result = PEP_CANNOT_SEND_KEY;
  2.1340 -                goto release_curl_ctx;
  2.1341 -            }
  2.1342 -        }
  2.1343 -    }
  2.1344 -
  2.1345 -release_curl_ctx:
  2.1346 -    curl_release_ctx(&curl);
  2.1347 -unlock_curl:
  2.1348 -    pthread_mutex_unlock(&session->ctx.curl_mutex);
  2.1349 -free_encoded_keys:
  2.1350 -    free_stringlist(encoded_keys);
  2.1351 -
  2.1352 -    return result;
  2.1353 -}
  2.1354 -
  2.1355 -
  2.1356 -PEP_STATUS pgp_get_key_rating(
  2.1357 -    PEP_SESSION session,
  2.1358 -    const char *fprstr,
  2.1359 -    PEP_comm_type *comm_type
  2.1360 -    )
  2.1361 -{
  2.1362 -    pgp_key_t *key;
  2.1363 -    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  2.1364 -    unsigned from = 0;
  2.1365 -    size_t length;
  2.1366 -
  2.1367 -
  2.1368 -    PEP_STATUS status = PEP_STATUS_OK;
  2.1369 -
  2.1370 -    assert(session);
  2.1371 -    assert(fprstr);
  2.1372 -    assert(comm_type);
  2.1373 -
  2.1374 -    if (!session || !fprstr || !comm_type )
  2.1375 -        return PEP_ILLEGAL_VALUE;
  2.1376 -
  2.1377 -    *comm_type = PEP_ct_unknown;
  2.1378 -
  2.1379 -    if(pthread_mutex_lock(&netpgp_mutex)){
  2.1380 -        return PEP_UNKNOWN_ERROR;
  2.1381 -    }
  2.1382 -
  2.1383 -    if (!str_to_fpr(fprstr, fpr, &length)) {
  2.1384 -        status = PEP_ILLEGAL_VALUE;
  2.1385 -        goto unlock_netpgp;
  2.1386 -    }
  2.1387 -        
  2.1388 -    key = pgp_getkeybyfpr(
  2.1389 -           netpgp.io,
  2.1390 -           netpgp.pubring,
  2.1391 -           fpr, length, &from, NULL,0,0);
  2.1392 -
  2.1393 -    if(key == NULL)
  2.1394 -    {
  2.1395 -        status = PEP_KEY_NOT_FOUND;
  2.1396 -        goto unlock_netpgp;
  2.1397 -    }
  2.1398 -
  2.1399 -    switch(pgp_key_get_rating(key)){
  2.1400 -	case PGP_VALID:
  2.1401 -        *comm_type = PEP_ct_OpenPGP_unconfirmed;
  2.1402 -        break;
  2.1403 -    case PGP_WEAK:
  2.1404 -        *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  2.1405 -        break;
  2.1406 -    case PGP_TOOSHORT:
  2.1407 -        *comm_type = PEP_ct_key_too_short;
  2.1408 -        break;
  2.1409 -	case PGP_INVALID:
  2.1410 -        *comm_type = PEP_ct_key_b0rken;
  2.1411 -        break;
  2.1412 -	case PGP_EXPIRED:
  2.1413 -        *comm_type = PEP_ct_key_expired;
  2.1414 -        break;
  2.1415 -    case PGP_REVOKED:
  2.1416 -        *comm_type = PEP_ct_key_revoked;
  2.1417 -        break;
  2.1418 -    default:
  2.1419 -        break;
  2.1420 -    }
  2.1421 -
  2.1422 -unlock_netpgp:
  2.1423 -    pthread_mutex_unlock(&netpgp_mutex);
  2.1424 -
  2.1425 -    return status;
  2.1426 -}
  2.1427 -
  2.1428 -PEP_STATUS pgp_renew_key(
  2.1429 -        PEP_SESSION session,
  2.1430 -        const char *fprstr,
  2.1431 -        const timestamp *ts
  2.1432 -    )
  2.1433 -{
  2.1434 -    pgp_key_t *pkey;
  2.1435 -    pgp_key_t *skey;
  2.1436 -    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  2.1437 -    size_t length;
  2.1438 -    unsigned from = 0;
  2.1439 -    time_t duration;
  2.1440 -    const uint8_t *primid;
  2.1441 -
  2.1442 -    PEP_STATUS status = PEP_STATUS_OK;
  2.1443 -
  2.1444 -    assert(session);
  2.1445 -    assert(fprstr);
  2.1446 -
  2.1447 -    if (!session || !fprstr )
  2.1448 -        return PEP_ILLEGAL_VALUE;
  2.1449 -
  2.1450 -    if(ts)
  2.1451 -    {
  2.1452 -        time_t    now, when;
  2.1453 -        now = time(NULL);
  2.1454 -        when = mktime((struct tm*)ts);
  2.1455 -        if(now && when && when > now){
  2.1456 -            duration = when - now;
  2.1457 -        }else{
  2.1458 -            return PEP_ILLEGAL_VALUE;
  2.1459 -        }
  2.1460 -    }else{
  2.1461 -        /* Default 1 year from now */
  2.1462 -        duration = 365*24*3600;
  2.1463 -    }
  2.1464 -
  2.1465 -    if(pthread_mutex_lock(&netpgp_mutex)){
  2.1466 -        return PEP_UNKNOWN_ERROR;
  2.1467 -    }
  2.1468 -
  2.1469 -    
  2.1470 -    if (!str_to_fpr(fprstr, fpr, &length)) {
  2.1471 -        status = PEP_ILLEGAL_VALUE;
  2.1472 -        goto unlock_netpgp;
  2.1473 -    }
  2.1474 -    
  2.1475 -    pkey = pgp_getkeybyfpr(
  2.1476 -                          netpgp.io,
  2.1477 -                          netpgp.pubring,
  2.1478 -                          fpr, length, &from, NULL,
  2.1479 -                          1, 0); /* reject revoked, accept expired */
  2.1480 -
  2.1481 -    if(pkey == NULL)
  2.1482 -    {
  2.1483 -        status = PEP_KEY_NOT_FOUND;
  2.1484 -        goto unlock_netpgp;
  2.1485 -    }
  2.1486 -
  2.1487 -    from = 0;
  2.1488 -    skey = pgp_getkeybyfpr(
  2.1489 -                           netpgp.io,
  2.1490 -                           netpgp.secring,
  2.1491 -                           fpr, length, &from, NULL,
  2.1492 -                           1, 0); /* reject revoked, accept expired */
  2.1493 -
  2.1494 -    if(skey == NULL)
  2.1495 -    {
  2.1496 -        status = PEP_KEY_NOT_FOUND;
  2.1497 -        goto unlock_netpgp;
  2.1498 -    }
  2.1499 -
  2.1500 -    if((primid = pgp_key_get_primary_userid(skey)) == NULL)
  2.1501 -    {
  2.1502 -        status = PEP_KEY_HAS_AMBIG_NAME;
  2.1503 -        goto unlock_netpgp;
  2.1504 -    }
  2.1505 -
  2.1506 -    // FIXME : renew in a more gentle way
  2.1507 -    if (!pgp_add_selfsigned_userid(skey, pkey, primid, duration))
  2.1508 -    {
  2.1509 -        status = PEP_CANNOT_CREATE_KEY;
  2.1510 -        goto unlock_netpgp;
  2.1511 -    }
  2.1512 -
  2.1513 -    // save rings
  2.1514 -    if (netpgp_save_pubring(&netpgp) &&
  2.1515 -        netpgp_save_secring(&netpgp))
  2.1516 -    {
  2.1517 -        status = PEP_STATUS_OK;
  2.1518 -    }else{
  2.1519 -        status = PEP_UNKNOWN_ERROR;
  2.1520 -    }
  2.1521 -    
  2.1522 -unlock_netpgp:
  2.1523 -    pthread_mutex_unlock(&netpgp_mutex);
  2.1524 -
  2.1525 -    return status;
  2.1526 -}
  2.1527 -
  2.1528 -PEP_STATUS pgp_revoke_key(
  2.1529 -        PEP_SESSION session,
  2.1530 -        const char *fprstr,
  2.1531 -        const char *reason
  2.1532 -    )
  2.1533 -{
  2.1534 -    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  2.1535 -    size_t length;
  2.1536 -    unsigned from = 0;
  2.1537 -
  2.1538 -    PEP_STATUS status = PEP_STATUS_OK;
  2.1539 -
  2.1540 -    assert(session);
  2.1541 -    assert(fprstr);
  2.1542 -
  2.1543 -    if (!session || !fprstr)
  2.1544 -        return PEP_UNKNOWN_ERROR;
  2.1545 -
  2.1546 -    if(pthread_mutex_lock(&netpgp_mutex)){
  2.1547 -        return PEP_UNKNOWN_ERROR;
  2.1548 -    }
  2.1549 -
  2.1550 -    // FIXME : deduplicate that code w/ renew
  2.1551 -    if (!str_to_fpr(fprstr, fpr, &length)) {
  2.1552 -        status = PEP_ILLEGAL_VALUE;
  2.1553 -        goto unlock_netpgp;
  2.1554 -    }
  2.1555 -    
  2.1556 -    pgp_key_t *pkey = pgp_getkeybyfpr(
  2.1557 -                           netpgp.io,
  2.1558 -                           netpgp.pubring,
  2.1559 -                           fpr, length, &from, NULL,
  2.1560 -                           1, 0); /* reject revoked, accept expired */
  2.1561 -    
  2.1562 -    if(pkey == NULL)
  2.1563 -    {
  2.1564 -        status = PEP_KEY_NOT_FOUND;
  2.1565 -        goto unlock_netpgp;
  2.1566 -    }
  2.1567 -    
  2.1568 -    from = 0;
  2.1569 -    pgp_key_t *skey = pgp_getkeybyfpr(
  2.1570 -                           netpgp.io,
  2.1571 -                           netpgp.secring,
  2.1572 -                           fpr, length, &from, NULL,
  2.1573 -                           1, 0); /* reject revoked, accept expired */
  2.1574 -    
  2.1575 -    if(skey == NULL)
  2.1576 -    {
  2.1577 -        status = PEP_KEY_NOT_FOUND;
  2.1578 -        goto unlock_netpgp;
  2.1579 -    }
  2.1580 -
  2.1581 -    pgp_key_revoke(skey, pkey,
  2.1582 -                   0, /* no reason code specified */
  2.1583 -                   reason);
  2.1584 -
  2.1585 -unlock_netpgp:
  2.1586 -    pthread_mutex_unlock(&netpgp_mutex);
  2.1587 -
  2.1588 -    return status;
  2.1589 -}
  2.1590 -
  2.1591 -PEP_STATUS pgp_key_expired(
  2.1592 -        PEP_SESSION session,
  2.1593 -        const char *fprstr,
  2.1594 -        const time_t when,
  2.1595 -        bool *expired
  2.1596 -    )
  2.1597 -{
  2.1598 -    PEP_STATUS status = PEP_STATUS_OK;
  2.1599 -    PEP_comm_type comm_type;
  2.1600 -
  2.1601 -    assert(session);
  2.1602 -    assert(fprstr);
  2.1603 -    assert(expired);
  2.1604 -
  2.1605 -    if (!session || !fprstr || !expired)
  2.1606 -        return PEP_UNKNOWN_ERROR;
  2.1607 -
  2.1608 -    // TODO : take "when" in account 
  2.1609 -
  2.1610 -    *expired = false;
  2.1611 -
  2.1612 -    status = pgp_get_key_rating(session, fprstr, &comm_type);
  2.1613 -
  2.1614 -    if (status != PEP_STATUS_OK)
  2.1615 -        return status;
  2.1616 -
  2.1617 -    if (comm_type == PEP_ct_key_expired){
  2.1618 -        *expired = true;
  2.1619 -    }
  2.1620 -
  2.1621 -    return PEP_STATUS_OK;
  2.1622 -}
  2.1623 -
  2.1624 -PEP_STATUS pgp_key_revoked(
  2.1625 -        PEP_SESSION session,
  2.1626 -        const char *fprstr,
  2.1627 -        bool *revoked
  2.1628 -    )
  2.1629 -{
  2.1630 -    PEP_STATUS status = PEP_STATUS_OK;
  2.1631 -    PEP_comm_type comm_type;
  2.1632 -    
  2.1633 -    assert(session);
  2.1634 -    assert(fprstr);
  2.1635 -    assert(revoked);
  2.1636 -    
  2.1637 -    *revoked = false;
  2.1638 -    
  2.1639 -    status = pgp_get_key_rating(session, fprstr, &comm_type);
  2.1640 -    
  2.1641 -    if (status != PEP_STATUS_OK)
  2.1642 -        return status;
  2.1643 -    
  2.1644 -    if (comm_type == PEP_ct_key_revoked){
  2.1645 -        *revoked = true;
  2.1646 -    }
  2.1647 -    
  2.1648 -    return PEP_STATUS_OK;
  2.1649 -}
  2.1650 -
  2.1651 -PEP_STATUS pgp_key_created(
  2.1652 -        PEP_SESSION session,
  2.1653 -        const char *fprstr,
  2.1654 -        time_t *created
  2.1655 -    )
  2.1656 -{
  2.1657 -    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  2.1658 -    pgp_key_t *key;
  2.1659 -    size_t length;
  2.1660 -    unsigned from = 0;
  2.1661 -
  2.1662 -    PEP_STATUS status = PEP_STATUS_OK;
  2.1663 -
  2.1664 -    assert(session);
  2.1665 -    assert(fprstr);
  2.1666 -    assert(created);
  2.1667 -
  2.1668 -    if (!session || !fprstr || !created)
  2.1669 -        return PEP_UNKNOWN_ERROR;
  2.1670 -
  2.1671 -    *created = 0;
  2.1672 -
  2.1673 -    if(pthread_mutex_lock(&netpgp_mutex)){
  2.1674 -        return PEP_UNKNOWN_ERROR;
  2.1675 -    }
  2.1676 -
  2.1677 -    if (!str_to_fpr(fprstr, fpr, &length)) {
  2.1678 -        status = PEP_ILLEGAL_VALUE;
  2.1679 -        goto unlock_netpgp;
  2.1680 -    }
  2.1681 -        
  2.1682 -    key = pgp_getkeybyfpr(
  2.1683 -           netpgp.io,
  2.1684 -           netpgp.pubring,
  2.1685 -           fpr, length, &from, NULL,0,0);
  2.1686 -
  2.1687 -    if (key)
  2.1688 -    {
  2.1689 -        *created = (time_t) key->key.pubkey.birthtime;
  2.1690 -    }
  2.1691 -    else
  2.1692 -    {
  2.1693 -        status = PEP_KEY_NOT_FOUND;
  2.1694 -        goto unlock_netpgp;
  2.1695 -    }
  2.1696 -    
  2.1697 -
  2.1698 -
  2.1699 -unlock_netpgp:
  2.1700 -    pthread_mutex_unlock(&netpgp_mutex);
  2.1701 -
  2.1702 -    return status;
  2.1703 -}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/pgp_netpgp.m	Wed Aug 03 18:56:31 2016 +0200
     3.3 @@ -0,0 +1,1748 @@
     3.4 +#include "pEp_internal.h"
     3.5 +#include "pgp_netpgp.h"
     3.6 +
     3.7 +#include <limits.h>
     3.8 +
     3.9 +#include "wrappers.h"
    3.10 +
    3.11 +#include "netpgp.h"
    3.12 +#include <netpgp/config.h>
    3.13 +#include <netpgp/memory.h>
    3.14 +#include <netpgp/crypto.h>
    3.15 +#include <netpgp/netpgpsdk.h>
    3.16 +#include <netpgp/validate.h>
    3.17 +#include <netpgp/readerwriter.h>
    3.18 +
    3.19 +#include <curl/curl.h>
    3.20 +#include <pthread.h>
    3.21 +#include <regex.h>
    3.22 +
    3.23 +#import <Foundation/Foundation.h>
    3.24 +
    3.25 +static netpgp_t netpgp;
    3.26 +static pthread_mutex_t netpgp_mutex;
    3.27 +
    3.28 +static NSString const *s_lockCount = @"s_lockCount";
    3.29 +
    3.30 +static int lock_the_mutex()
    3.31 +{
    3.32 +    NSMutableDictionary *lockCounts = [[NSThread currentThread] threadDictionary];
    3.33 +    NSNumber *num = lockCounts[s_lockCount];
    3.34 +
    3.35 +    if (!num) {
    3.36 +        num = [NSNumber numberWithInteger:0];
    3.37 +    }
    3.38 +
    3.39 +    NSNumber *nextNum = [NSNumber numberWithInteger:[num integerValue] + 1];
    3.40 +    lockCounts[s_lockCount] = nextNum;
    3.41 +
    3.42 +    NSLog(@"mutex lock (%ld)", (long)[nextNum integerValue]);
    3.43 +
    3.44 +    if ([nextNum integerValue] > 1) {
    3.45 +        NSLog(@"mutex lock alarm (%ld)", (long)[nextNum integerValue]);
    3.46 +    }
    3.47 +
    3.48 +    int status = pthread_mutex_trylock(&netpgp_mutex);
    3.49 +
    3.50 +    if (status == EBUSY) {
    3.51 +        NSLog(@"mutex is busy (%ld)", (long)[nextNum integerValue]);
    3.52 +        status = pthread_mutex_lock(&netpgp_mutex);
    3.53 +    }
    3.54 +    return status;
    3.55 +}
    3.56 +
    3.57 +static int unlock_the_mutex()
    3.58 +{
    3.59 +    NSMutableDictionary *lockCounts = [[NSThread currentThread] threadDictionary];
    3.60 +    NSNumber *num = lockCounts[s_lockCount];
    3.61 +
    3.62 +    NSNumber *nextNum = [NSNumber numberWithInteger:[num integerValue] - 1];
    3.63 +    lockCounts[s_lockCount] = nextNum;
    3.64 +
    3.65 +    NSLog(@"mutex unlock (%ld)", (long)[nextNum integerValue]);
    3.66 +
    3.67 +    if ([nextNum integerValue] != 0) {
    3.68 +        NSLog(@"mutex unlock alarm (%ld)", (long)[nextNum integerValue]);
    3.69 +    }
    3.70 +
    3.71 +    return pthread_mutex_unlock(&netpgp_mutex);
    3.72 +}
    3.73 +
    3.74 +static PEP_STATUS init_netpgp()
    3.75 +{
    3.76 +    PEP_STATUS status = PEP_STATUS_OK;
    3.77 +    const char *home = NULL;
    3.78 +
    3.79 +    if(pthread_mutex_init(&netpgp_mutex, NULL)){
    3.80 +        return PEP_OUT_OF_MEMORY;
    3.81 +    }
    3.82 +
    3.83 +    if(lock_the_mutex()){
    3.84 +        return PEP_UNKNOWN_ERROR;
    3.85 +    }
    3.86 +
    3.87 +    if (strcmp(setlocale(LC_ALL, NULL), "C") == 0)
    3.88 +        setlocale(LC_ALL, "");
    3.89 +
    3.90 +    memset(&netpgp, 0x0, sizeof(netpgp_t));
    3.91 +
    3.92 +    // netpgp_setvar(&netpgp, "max mem alloc", "4194304");
    3.93 +    netpgp_setvar(&netpgp, "need seckey", "1");
    3.94 +    // netpgp_setvar(&netpgp, "need userid", "1");
    3.95 +
    3.96 +    // NetPGP shares home with GPG
    3.97 +    home = gpg_home();
    3.98 +    if(home){
    3.99 +        netpgp_set_homedir(&netpgp,(char*)home, NULL, 0);
   3.100 +    }else{
   3.101 +        status = PEP_INIT_NO_GPG_HOME;
   3.102 +        goto unlock_netpgp;
   3.103 +    }
   3.104 +
   3.105 +    // pair with gpg's cert-digest-algo
   3.106 +    netpgp_setvar(&netpgp, "hash", "SHA256");
   3.107 +
   3.108 +    // subset of gpg's personal-cipher-preferences
   3.109 +    // here only one cipher can be selected
   3.110 +    netpgp_setvar(&netpgp, "cipher", "CAST5");
   3.111 +
   3.112 +    if (!netpgp_init(&netpgp)) {
   3.113 +        status = PEP_INIT_NETPGP_INIT_FAILED;
   3.114 +        goto unlock_netpgp;
   3.115 +    }
   3.116 +
   3.117 +    // netpgp_set_debug("packet-parse.c");
   3.118 +
   3.119 +unlock_netpgp:
   3.120 +    unlock_the_mutex();
   3.121 +    
   3.122 +    return status;
   3.123 +}
   3.124 +
   3.125 +static void release_netpgp()
   3.126 +{
   3.127 +    if(lock_the_mutex()){
   3.128 +        return;
   3.129 +    }
   3.130 +    netpgp_end(&netpgp);
   3.131 +    memset(&netpgp, 0x0, sizeof(netpgp_t));
   3.132 +
   3.133 +    pthread_mutex_destroy(&netpgp_mutex);
   3.134 +
   3.135 +    return;
   3.136 +}
   3.137 +
   3.138 +static PEP_STATUS init_curl(
   3.139 +    pthread_mutex_t *curl_mutex,
   3.140 +    bool in_first)
   3.141 +{
   3.142 +    PEP_STATUS status = PEP_STATUS_OK;
   3.143 +
   3.144 +    if(pthread_mutex_init(curl_mutex, NULL)){
   3.145 +        return PEP_OUT_OF_MEMORY;
   3.146 +    }
   3.147 +
   3.148 +    if(pthread_mutex_lock(curl_mutex)){
   3.149 +        return PEP_UNKNOWN_ERROR;
   3.150 +    }
   3.151 +
   3.152 +    if(in_first){
   3.153 +        curl_global_init(CURL_GLOBAL_DEFAULT);
   3.154 +    }
   3.155 +
   3.156 +    pthread_mutex_unlock(curl_mutex);
   3.157 +    return status;
   3.158 +}
   3.159 +
   3.160 +static void release_curl(
   3.161 +    pthread_mutex_t *curl_mutex, 
   3.162 +    bool out_last)
   3.163 +{
   3.164 +    if(pthread_mutex_lock(curl_mutex)){
   3.165 +        return;
   3.166 +    }
   3.167 +
   3.168 +    if(out_last){
   3.169 +        curl_global_cleanup();
   3.170 +    }
   3.171 +
   3.172 +    pthread_mutex_destroy(curl_mutex);
   3.173 +
   3.174 +    return;
   3.175 +}
   3.176 +
   3.177 +static PEP_STATUS curl_get_ctx(
   3.178 +    CURL **curl)
   3.179 +{
   3.180 +    PEP_STATUS status = PEP_STATUS_OK;
   3.181 +    struct curl_slist *headers=NULL;
   3.182 +
   3.183 +    if ((*curl = curl_easy_init()) == NULL) {
   3.184 +        return PEP_OUT_OF_MEMORY;
   3.185 +    }
   3.186 +
   3.187 +    curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
   3.188 +    curl_easy_setopt(*curl, CURLOPT_MAXREDIRS, 3L);
   3.189 +
   3.190 +    headers=curl_slist_append(headers,"Pragma: no-cache");
   3.191 +    if(headers)
   3.192 +        headers=curl_slist_append(headers,"Cache-Control: no-cache");
   3.193 +
   3.194 +    if(!headers)
   3.195 +    {
   3.196 +        return PEP_OUT_OF_MEMORY;
   3.197 +    }
   3.198 +
   3.199 +    curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);
   3.200 +    curl_slist_free_all(headers);
   3.201 +
   3.202 +    // TODO curl_easy_setopt(curl,CURLOPT_PROXY,proxy);
   3.203 +    return status;
   3.204 +}
   3.205 +
   3.206 +static void curl_release_ctx(
   3.207 +    CURL **curl)
   3.208 +{
   3.209 +    if(*curl)
   3.210 +        curl_easy_cleanup(*curl);
   3.211 +
   3.212 +    *curl = NULL;
   3.213 +
   3.214 +    return;
   3.215 +}
   3.216 +
   3.217 +PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
   3.218 +{
   3.219 +    PEP_STATUS status = PEP_STATUS_OK;
   3.220 +
   3.221 +    assert(session);
   3.222 +    if(!session) return PEP_ILLEGAL_VALUE;
   3.223 +
   3.224 +    if (in_first) {
   3.225 +        if((status = init_netpgp()) != PEP_STATUS_OK)
   3.226 +        return status;
   3.227 +    }
   3.228 +
   3.229 +    if((status = init_curl(
   3.230 +                    &session->ctx.curl_mutex,
   3.231 +                    in_first) != PEP_STATUS_OK)){
   3.232 +        if(in_first) release_netpgp();
   3.233 +        return status;
   3.234 +    }
   3.235 +
   3.236 +    return PEP_STATUS_OK;
   3.237 +}
   3.238 +
   3.239 +void pgp_release(PEP_SESSION session, bool out_last)
   3.240 +{
   3.241 +    assert(session);
   3.242 +    if(!session) return;
   3.243 +
   3.244 +    if (out_last){
   3.245 +        release_netpgp();
   3.246 +    }
   3.247 +    release_curl(&session->ctx.curl_mutex, out_last);
   3.248 +}
   3.249 +
   3.250 +// return 1 if the file contains ascii-armoured text
   3.251 +static unsigned
   3.252 +_armoured(const char *buf, size_t size, const char *pattern)
   3.253 +{
   3.254 +    unsigned armoured = 0;
   3.255 +    regex_t r;
   3.256 +    regcomp(&r, pattern, REG_EXTENDED|REG_NOSUB);
   3.257 +    if (regnexec(&r, buf, size, 0, NULL, 0) == 0) {
   3.258 +        armoured = 1;
   3.259 +    }
   3.260 +    regfree(&r);
   3.261 +    return armoured;
   3.262 +}
   3.263 +
   3.264 +/* write key fingerprint hexdump as a string */
   3.265 +static unsigned
   3.266 +fpr_to_str (char **str, const uint8_t *fpr, size_t length)
   3.267 +{
   3.268 +    unsigned i;
   3.269 +    int	n;
   3.270 +    
   3.271 +    /* 4 hexes per short + null */
   3.272 +    *str = malloc((length / 2) * 4 + 1);
   3.273 +    
   3.274 +    if(*str == NULL)
   3.275 +        return 0;
   3.276 +    
   3.277 +    for (n = 0, i = 0 ; i < length; i += 2) {
   3.278 +        n += snprintf(&((*str)[n]), 5, "%02x%02x", fpr[i], fpr[i+1]);
   3.279 +    }
   3.280 +    
   3.281 +    return 1;
   3.282 +}
   3.283 +
   3.284 +/* write key fingerprint bytes read from hex string
   3.285 + * accept spaces and hexes */
   3.286 +static unsigned
   3.287 +str_to_fpr (const char *str, uint8_t *fpr, size_t *length)
   3.288 +{
   3.289 +    unsigned i,j;
   3.290 +    
   3.291 +    *length = 0;
   3.292 +    
   3.293 +    while(*str && *length < PGP_FINGERPRINT_SIZE){
   3.294 +        while (*str == ' ') str++;
   3.295 +        for (j = 0; j < 2; j++) {
   3.296 +            uint8_t *byte = &fpr[*length];
   3.297 +            *byte = 0;
   3.298 +            for (i = 0; i < 2; i++) {
   3.299 +                if (i > 0)
   3.300 +                    *byte = *byte << 4;
   3.301 +                if (*str >= 'a' && *str <= 'f')
   3.302 +                    *byte += 10 + *str - 'a';
   3.303 +                else if (*str >= 'A' && *str <= 'F')
   3.304 +                    *byte += 10 + *str - 'A';
   3.305 +                else if (*str >= '0' && *str <= '9')
   3.306 +                    *byte += *str - '0';
   3.307 +                else
   3.308 +                    return 0;
   3.309 +                str++;
   3.310 +            }
   3.311 +            (*length)++;
   3.312 +        }
   3.313 +    }
   3.314 +    return 1;
   3.315 +}
   3.316 +
   3.317 +// Iterate through netpgp' reported valid signatures 
   3.318 +// fill a list of valid figerprints
   3.319 +// returns PEP_STATUS_OK if all sig reported valid
   3.320 +// error status otherwise.
   3.321 +static PEP_STATUS _validation_results(
   3.322 +        netpgp_t *netpgp,
   3.323 +        pgp_validation_t *vresult,
   3.324 +        stringlist_t **_keylist
   3.325 +    )
   3.326 +{
   3.327 +    time_t    now;
   3.328 +    time_t    t;
   3.329 +
   3.330 +    now = time(NULL);
   3.331 +    if (now < vresult->birthtime) {
   3.332 +        // signature is not valid yet
   3.333 +        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   3.334 +    }
   3.335 +    if (vresult->duration != 0 && now > vresult->birthtime + vresult->duration) {
   3.336 +        // signature has expired
   3.337 +        t = vresult->duration + vresult->birthtime;
   3.338 +        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   3.339 +    }
   3.340 +    if (vresult->validc && vresult->valid_sigs &&
   3.341 +        !vresult->invalidc && !vresult->unknownc ) {
   3.342 +        unsigned    n;
   3.343 +        stringlist_t *k;
   3.344 +        // caller responsible to free
   3.345 +        *_keylist = new_stringlist(NULL);
   3.346 +        assert(*_keylist);
   3.347 +        if (*_keylist == NULL) {
   3.348 +            return PEP_OUT_OF_MEMORY;
   3.349 +        }
   3.350 +        k = *_keylist;
   3.351 +        for (n = 0; n < vresult->validc; ++n) {
   3.352 +            unsigned from = 0;
   3.353 +            const pgp_key_t	 *signer;
   3.354 +            char *fprstr = NULL;
   3.355 +            const uint8_t *keyid = vresult->valid_sigs[n].signer_id;
   3.356 +            
   3.357 +            signer = pgp_getkeybyid(netpgp->io, netpgp->pubring,
   3.358 +                                    keyid, &from, NULL, NULL,
   3.359 +                                    0, 0); /* check neither revocation nor expiry 
   3.360 +                                              as is should be checked already */
   3.361 +            if(signer)
   3.362 +                fpr_to_str(&fprstr,
   3.363 +                           signer->pubkeyfpr.fingerprint,
   3.364 +                           signer->pubkeyfpr.length);
   3.365 +            else
   3.366 +                return PEP_VERIFY_NO_KEY;
   3.367 +            
   3.368 +            if (fprstr == NULL)
   3.369 +                return PEP_OUT_OF_MEMORY;
   3.370 +            
   3.371 +            k = stringlist_add(k, fprstr);
   3.372 +            
   3.373 +            free(fprstr);
   3.374 +            
   3.375 +            if(!k){
   3.376 +                free_stringlist(*_keylist);
   3.377 +                return PEP_OUT_OF_MEMORY;
   3.378 +            }
   3.379 +        }
   3.380 +        return PEP_STATUS_OK;
   3.381 +    }
   3.382 +    if (vresult->validc + vresult->invalidc + vresult->unknownc == 0) {
   3.383 +        // No signatures found - is this memory signed?
   3.384 +        return PEP_VERIFY_NO_KEY; 
   3.385 +    } 
   3.386 +    
   3.387 +    if (vresult->invalidc) {
   3.388 +        // some invalid signatures
   3.389 +        return PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
   3.390 +    }
   3.391 +    
   3.392 +    // only unknown sigs
   3.393 +    return PEP_DECRYPTED;
   3.394 +}
   3.395 +
   3.396 +#define _ENDL    "\\s*(\r\n|\r|\n)"
   3.397 +#define ARMOR_HEAD    "^-----BEGIN PGP MESSAGE-----"_ENDL
   3.398 +PEP_STATUS pgp_decrypt_and_verify(
   3.399 +    PEP_SESSION session, const char *ctext, size_t csize,
   3.400 +    char **ptext, size_t *psize, stringlist_t **keylist
   3.401 +    )
   3.402 +{
   3.403 +    pgp_memory_t *mem;
   3.404 +    pgp_validation_t *vresult;
   3.405 +    char *_ptext = NULL;
   3.406 +    size_t _psize = 0;
   3.407 +
   3.408 +    PEP_STATUS result;
   3.409 +    stringlist_t *_keylist = NULL;
   3.410 +
   3.411 +    assert(session);
   3.412 +    assert(ctext);
   3.413 +    assert(csize);
   3.414 +    assert(ptext);
   3.415 +    assert(psize);
   3.416 +    assert(keylist);
   3.417 +
   3.418 +    if(!session || !ctext || !csize || !ptext || !psize || !keylist) 
   3.419 +        return PEP_ILLEGAL_VALUE;
   3.420 +
   3.421 +    if(lock_the_mutex()){
   3.422 +        return PEP_UNKNOWN_ERROR;
   3.423 +    }
   3.424 +
   3.425 +    *ptext = NULL;
   3.426 +    *psize = 0;
   3.427 +    *keylist = NULL;
   3.428 +
   3.429 +    vresult = malloc(sizeof(pgp_validation_t));
   3.430 +    memset(vresult, 0x0, sizeof(pgp_validation_t));
   3.431 +
   3.432 +    mem = pgp_decrypt_and_validate_buf(netpgp.io, vresult, ctext, csize,
   3.433 +                netpgp.secring, netpgp.pubring,
   3.434 +                _armoured(ctext, csize, ARMOR_HEAD),
   3.435 +                0 /* sshkeys */,
   3.436 +                NULL, -1, NULL  /* pass fp,attempts,cb */);
   3.437 +    if (mem == NULL) {
   3.438 +        result = PEP_OUT_OF_MEMORY;
   3.439 +        goto unlock_netpgp;
   3.440 +    }
   3.441 +
   3.442 +    _psize = pgp_mem_len(mem);
   3.443 +    if (_psize){
   3.444 +        if ((_ptext = malloc(_psize + 1)) == NULL) {
   3.445 +            result = PEP_OUT_OF_MEMORY;
   3.446 +            goto free_pgp;
   3.447 +        }
   3.448 +        memcpy(_ptext, pgp_mem_data(mem), _psize);
   3.449 +        _ptext[_psize] = '\0'; // safeguard for naive users
   3.450 +        result = PEP_DECRYPTED;
   3.451 +    }else{
   3.452 +        result = PEP_DECRYPT_NO_KEY;
   3.453 +        goto free_pgp;
   3.454 +    }
   3.455 +
   3.456 +    if (result == PEP_DECRYPTED) {
   3.457 +        result = _validation_results(&netpgp, vresult, &_keylist);
   3.458 +        if (result == PEP_DECRYPTED) {
   3.459 +            //no change
   3.460 +        } else if (result == PEP_VERIFY_NO_KEY) {
   3.461 +            result = PEP_DECRYPTED;
   3.462 +        }else if (result != PEP_STATUS_OK) {
   3.463 +            goto free_ptext;
   3.464 +        }else{
   3.465 +            result = PEP_DECRYPTED_AND_VERIFIED;
   3.466 +        }
   3.467 +    }
   3.468 +
   3.469 +    if (result == PEP_DECRYPTED_AND_VERIFIED
   3.470 +        || result == PEP_DECRYPTED) {
   3.471 +        *ptext = _ptext;
   3.472 +        *psize = _psize;
   3.473 +        (*ptext)[*psize] = 0; // safeguard for naive users
   3.474 +        if (result == PEP_DECRYPTED_AND_VERIFIED) {
   3.475 +            *keylist = _keylist;
   3.476 +        }
   3.477 +
   3.478 +        /* _ptext and _keylist ownership transfer, don't free */
   3.479 +        goto free_pgp;
   3.480 +    }
   3.481 +
   3.482 +free_keylist:
   3.483 +    free_stringlist(_keylist);
   3.484 +
   3.485 +free_ptext:
   3.486 +    free(_ptext);
   3.487 +
   3.488 +free_pgp:
   3.489 +    pgp_memory_free(mem);
   3.490 +    pgp_validate_result_free(vresult);
   3.491 +
   3.492 +unlock_netpgp:
   3.493 +    unlock_the_mutex();
   3.494 +
   3.495 +    return result;
   3.496 +}
   3.497 +
   3.498 +#define ARMOR_SIG_HEAD    "^-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"_ENDL
   3.499 +PEP_STATUS pgp_verify_text(
   3.500 +    PEP_SESSION session, const char *text, size_t size,
   3.501 +    const char *signature, size_t sig_size, stringlist_t **keylist
   3.502 +    )
   3.503 +{
   3.504 +    pgp_memory_t *signedmem;
   3.505 +    pgp_memory_t *sig;
   3.506 +    pgp_validation_t *vresult;
   3.507 +
   3.508 +    PEP_STATUS result;
   3.509 +    stringlist_t *_keylist;
   3.510 +
   3.511 +    assert(session);
   3.512 +    assert(text);
   3.513 +    assert(size);
   3.514 +    assert(signature);
   3.515 +    assert(sig_size);
   3.516 +    assert(keylist);
   3.517 +
   3.518 +    if(!session || !text || !size || !signature || !sig_size || !keylist) 
   3.519 +        return PEP_ILLEGAL_VALUE;
   3.520 +
   3.521 +    if(lock_the_mutex()){
   3.522 +        return PEP_UNKNOWN_ERROR;
   3.523 +    }
   3.524 +
   3.525 +    *keylist = NULL;
   3.526 +
   3.527 +    vresult = malloc(sizeof(pgp_validation_t));
   3.528 +    if (vresult == NULL) {
   3.529 +        result = PEP_OUT_OF_MEMORY;
   3.530 +        goto unlock_netpgp;
   3.531 +    }
   3.532 +    memset(vresult, 0x0, sizeof(pgp_validation_t));
   3.533 +
   3.534 +    signedmem = pgp_memory_new();
   3.535 +    if (signedmem == NULL) {
   3.536 +        result = PEP_OUT_OF_MEMORY;
   3.537 +        goto unlock_netpgp;
   3.538 +    }
   3.539 +    pgp_memory_add(signedmem, (const uint8_t*)text, size);
   3.540 +
   3.541 +    sig = pgp_memory_new();
   3.542 +    if (sig == NULL) {
   3.543 +        pgp_memory_free(signedmem);
   3.544 +        result = PEP_OUT_OF_MEMORY;
   3.545 +        goto unlock_netpgp;
   3.546 +    }
   3.547 +    pgp_memory_add(sig, (const uint8_t*)signature, sig_size);
   3.548 +
   3.549 +    pgp_validate_mem_detached(netpgp.io, vresult, sig,
   3.550 +                NULL,/* output */
   3.551 +                _armoured(signature, sig_size, ARMOR_SIG_HEAD),
   3.552 +                netpgp.pubring,
   3.553 +                signedmem);
   3.554 +
   3.555 +    result = _validation_results(&netpgp, vresult, &_keylist);
   3.556 +    if (result != PEP_STATUS_OK) {
   3.557 +        goto free_pgp;
   3.558 +    }else{
   3.559 +        result = PEP_VERIFIED;
   3.560 +    }
   3.561 +
   3.562 +    if (result == PEP_VERIFIED) {
   3.563 +        /* TODO : check trust level */
   3.564 +        result = PEP_VERIFIED_AND_TRUSTED;
   3.565 +    }
   3.566 +
   3.567 +    if (result == PEP_VERIFIED || result == PEP_VERIFIED_AND_TRUSTED) {
   3.568 +        *keylist = _keylist;
   3.569 +
   3.570 +        /* _keylist ownership transfer, don't free */
   3.571 +        goto free_pgp;
   3.572 +    }
   3.573 +
   3.574 +free_keylist:
   3.575 +    free_stringlist(_keylist);
   3.576 +
   3.577 +free_pgp:
   3.578 +    // free done by pgp_validate_mem_detached
   3.579 +    // pgp_memory_free(sig);
   3.580 +    // pgp_memory_free(signedmem);
   3.581 +    pgp_validate_result_free(vresult);
   3.582 +
   3.583 +unlock_netpgp:
   3.584 +    unlock_the_mutex();
   3.585 +
   3.586 +    return result;
   3.587 +}
   3.588 +
   3.589 +PEP_STATUS pgp_encrypt_and_sign(
   3.590 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   3.591 +    size_t psize, char **ctext, size_t *csize
   3.592 +    )
   3.593 +{
   3.594 +    pgp_key_t *signer = NULL;
   3.595 +    pgp_seckey_t *seckey = NULL;
   3.596 +    pgp_memory_t *signedmem;
   3.597 +    pgp_memory_t *cmem;
   3.598 +    const char *hashalg;
   3.599 +    pgp_keyring_t *rcpts;
   3.600 +
   3.601 +    PEP_STATUS result;
   3.602 +    const stringlist_t *_keylist;
   3.603 +
   3.604 +    assert(session);
   3.605 +    assert(keylist);
   3.606 +    assert(ptext);
   3.607 +    assert(psize);
   3.608 +    assert(ctext);
   3.609 +    assert(csize);
   3.610 +
   3.611 +    if(!session || !ptext || !psize || !ctext || !csize || !keylist) 
   3.612 +        return PEP_ILLEGAL_VALUE;
   3.613 +
   3.614 +    if(lock_the_mutex()){
   3.615 +        return PEP_UNKNOWN_ERROR;
   3.616 +    }
   3.617 +
   3.618 +    *ctext = NULL;
   3.619 +    *csize = 0;
   3.620 +
   3.621 +    if ((rcpts = calloc(1, sizeof(*rcpts))) == NULL) {
   3.622 +        result = PEP_OUT_OF_MEMORY;
   3.623 +        goto unlock_netpgp;
   3.624 +    }
   3.625 +    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
   3.626 +        assert(_keylist->value);
   3.627 +        
   3.628 +        const pgp_key_t *key;
   3.629 +        uint8_t fpr[PGP_FINGERPRINT_SIZE];
   3.630 +        size_t fprlen;
   3.631 +        unsigned from = 0;
   3.632 +
   3.633 +        if (str_to_fpr(_keylist->value, fpr, &fprlen)) {
   3.634 +            if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
   3.635 +                                                    fpr, fprlen, &from, NULL,
   3.636 +                                                    /* reject revoked, accept expired */
   3.637 +                                                    1,0)) == NULL) {
   3.638 +                result = PEP_KEY_NOT_FOUND;
   3.639 +                goto free_rcpts;
   3.640 +            }
   3.641 +        }else{
   3.642 +            result = PEP_ILLEGAL_VALUE;
   3.643 +            goto free_rcpts;
   3.644 +        }
   3.645 +
   3.646 +        /* Signer is the first key in the list */
   3.647 +        if(signer == NULL){
   3.648 +            from = 0;
   3.649 +            signer = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.secring,
   3.650 +                                                  fpr, fprlen,
   3.651 +                                                  &from,
   3.652 +                                                  NULL,
   3.653 +                                                  0,0); /* accept any */
   3.654 +            if(signer == NULL){
   3.655 +                result = PEP_KEY_NOT_FOUND;
   3.656 +                goto free_rcpts;
   3.657 +            }
   3.658 +        }
   3.659 +
   3.660 +        // add key to recipients/signers
   3.661 +        pgp_keyring_add(rcpts, key);
   3.662 +        if(rcpts->keys == NULL){
   3.663 +            result = PEP_OUT_OF_MEMORY;
   3.664 +            goto free_rcpts;
   3.665 +        }
   3.666 +    }
   3.667 +
   3.668 +    /* Empty keylist ?*/
   3.669 +    if(rcpts->keyc == 0){
   3.670 +        result = PEP_ILLEGAL_VALUE;
   3.671 +        goto free_rcpts;
   3.672 +    }
   3.673 +
   3.674 +    seckey = pgp_key_get_certkey(signer);
   3.675 +
   3.676 +    /* No signig key. Revoked ? */
   3.677 +    if(seckey == NULL){
   3.678 +        result = PEP_GET_KEY_FAILED;
   3.679 +        goto free_rcpts;
   3.680 +    }
   3.681 +
   3.682 +    hashalg = netpgp_getvar(&netpgp, "hash");
   3.683 +
   3.684 +    // Sign data
   3.685 +    signedmem = pgp_sign_buf(netpgp.io, ptext, psize, seckey,
   3.686 +                time(NULL), /* birthtime */
   3.687 +                0 /* duration */,
   3.688 +                hashalg, 
   3.689 +                0 /* armored */,
   3.690 +                0 /* cleartext */);
   3.691 +
   3.692 +    if (!signedmem) {
   3.693 +        result = PEP_UNENCRYPTED;
   3.694 +        goto free_rcpts;
   3.695 +    }
   3.696 +
   3.697 +    // Encrypt signed data
   3.698 +
   3.699 +    cmem = pgp_encrypt_buf(netpgp.io, pgp_mem_data(signedmem),
   3.700 +            pgp_mem_len(signedmem), rcpts, 1 /* armored */,
   3.701 +            netpgp_getvar(&netpgp, "cipher"), 
   3.702 +            1 /* takes raw OpenPGP message */);
   3.703 +
   3.704 +    if (cmem == NULL) {
   3.705 +        result = PEP_OUT_OF_MEMORY;
   3.706 +        goto free_signedmem;
   3.707 +    }else{
   3.708 +
   3.709 +        char *_buffer = NULL;
   3.710 +        size_t length = pgp_mem_len(cmem);
   3.711 +
   3.712 +        // Allocate transferable buffer
   3.713 +        _buffer = malloc(length + 1);
   3.714 +        assert(_buffer);
   3.715 +        if (_buffer == NULL) {
   3.716 +            result = PEP_OUT_OF_MEMORY;
   3.717 +            goto free_cmem;
   3.718 +        }
   3.719 +
   3.720 +        memcpy(_buffer, pgp_mem_data(cmem), length);
   3.721 +
   3.722 +        *ctext = _buffer;
   3.723 +        *csize = length;
   3.724 +        (*ctext)[*csize] = 0; // safeguard for naive users
   3.725 +        result = PEP_STATUS_OK;
   3.726 +    }
   3.727 +
   3.728 +free_cmem :
   3.729 +    pgp_memory_free(cmem);
   3.730 +free_signedmem :
   3.731 +    pgp_memory_free(signedmem);
   3.732 +free_rcpts :
   3.733 +    pgp_keyring_free(rcpts);
   3.734 +unlock_netpgp:
   3.735 +    unlock_the_mutex();
   3.736 +
   3.737 +    return result;
   3.738 +}
   3.739 +
   3.740 +PEP_STATUS pgp_generate_keypair(
   3.741 +    PEP_SESSION session, pEp_identity *identity
   3.742 +    )
   3.743 +{
   3.744 +    pgp_key_t	newseckey;
   3.745 +    pgp_key_t	*newpubkey;
   3.746 +
   3.747 +    PEP_STATUS result;
   3.748 +    char newid[1024];
   3.749 +    const char *hashalg;
   3.750 +    const char *cipher;
   3.751 +
   3.752 +    assert(session);
   3.753 +    assert(identity);
   3.754 +    assert(identity->address);
   3.755 +    assert(identity->fpr == NULL);
   3.756 +    assert(identity->username);
   3.757 +
   3.758 +    if(!session || !identity || 
   3.759 +       !identity->address || identity->fpr || !identity->username)
   3.760 +        return PEP_ILLEGAL_VALUE;
   3.761 +
   3.762 +    if(lock_the_mutex()){
   3.763 +        return PEP_UNKNOWN_ERROR;
   3.764 +    }
   3.765 +
   3.766 +    if(snprintf(newid, sizeof(newid),
   3.767 +        "%s <%s>", identity->username, identity->address) >= sizeof(newid)){
   3.768 +        result =  PEP_BUFFER_TOO_SMALL;
   3.769 +        goto unlock_netpgp;
   3.770 +    }
   3.771 +    
   3.772 +    hashalg = netpgp_getvar(&netpgp, "hash");
   3.773 +    cipher = netpgp_getvar(&netpgp, "cipher");
   3.774 +
   3.775 +    bzero(&newseckey, sizeof(newseckey));
   3.776 +
   3.777 +    // Generate the key
   3.778 +    if (!pgp_rsa_generate_keypair(&newseckey, 4096, 65537UL, hashalg, cipher,
   3.779 +                                  (const uint8_t *) "", (const size_t) 0))
   3.780 +    {
   3.781 +        result = PEP_CANNOT_CREATE_KEY;
   3.782 +        goto free_seckey;
   3.783 +    }
   3.784 +
   3.785 +    /* make a public key out of generated secret key */
   3.786 +    if((newpubkey = pgp_ensure_pubkey(
   3.787 +            netpgp.pubring,
   3.788 +            &newseckey.key.seckey.pubkey,
   3.789 +            newseckey.pubkeyid))==NULL)
   3.790 +    {
   3.791 +        result = PEP_OUT_OF_MEMORY;
   3.792 +        goto free_seckey;
   3.793 +    }
   3.794 +
   3.795 +    // "Expire-Date: 1y\n";
   3.796 +    if (!pgp_add_selfsigned_userid(&newseckey, newpubkey, 
   3.797 +                                  (uint8_t *)newid, 365*24*3600))
   3.798 +    {
   3.799 +        result = PEP_CANNOT_CREATE_KEY;
   3.800 +        goto delete_pubkey;
   3.801 +    }
   3.802 +
   3.803 +    if (newpubkey == NULL)
   3.804 +    {
   3.805 +        result = PEP_OUT_OF_MEMORY;
   3.806 +        goto delete_pubkey;
   3.807 +    }
   3.808 +
   3.809 +    // Append key to netpgp's rings (key ownership transfered)
   3.810 +    if (!pgp_keyring_add(netpgp.secring, &newseckey)){
   3.811 +        result = PEP_OUT_OF_MEMORY;
   3.812 +        goto delete_pubkey;
   3.813 +    } 
   3.814 +
   3.815 +    // save rings 
   3.816 +    if (netpgp_save_pubring(&netpgp) && netpgp_save_secring(&netpgp))
   3.817 +    {
   3.818 +        char *fprstr = NULL;
   3.819 +        fpr_to_str(&fprstr,
   3.820 +                   newseckey.pubkeyfpr.fingerprint,
   3.821 +                   newseckey.pubkeyfpr.length);
   3.822 +
   3.823 +        if (fprstr == NULL) {
   3.824 +            result = PEP_OUT_OF_MEMORY;
   3.825 +            goto pop_secring;
   3.826 +        } 
   3.827 +
   3.828 +        /* keys saved, pass fingerprint back */
   3.829 +        identity->fpr = fprstr;
   3.830 +        result = PEP_STATUS_OK;
   3.831 +
   3.832 +        /* free nothing, everything transfered */
   3.833 +        goto unlock_netpgp;
   3.834 +    } else {
   3.835 +        /* XXX in case only pubring save succeed
   3.836 +         * pubring file is left as-is, but backup restore
   3.837 +         * could be attempted if such corner case matters */
   3.838 +        result = PEP_UNKNOWN_ERROR;
   3.839 +    }
   3.840 +
   3.841 +pop_secring:
   3.842 +    ((pgp_keyring_t *)netpgp.secring)->keyc--;
   3.843 +delete_pubkey:
   3.844 +    pgp_deletekeybyfpr(netpgp.io,
   3.845 +                    (pgp_keyring_t *)netpgp.pubring, 
   3.846 +                    newseckey.pubkeyfpr.fingerprint,
   3.847 +                    newseckey.pubkeyfpr.length);
   3.848 +free_seckey:
   3.849 +    pgp_key_free(&newseckey);
   3.850 +unlock_netpgp:
   3.851 +    unlock_the_mutex();
   3.852 +
   3.853 +    return result;
   3.854 +}
   3.855 +
   3.856 +PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fprstr)
   3.857 +{
   3.858 +    uint8_t fpr[PGP_FINGERPRINT_SIZE];
   3.859 +    size_t length;
   3.860 +
   3.861 +    PEP_STATUS result;
   3.862 +
   3.863 +    assert(session);
   3.864 +    assert(fprstr);
   3.865 +
   3.866 +    if (!session || !fprstr)
   3.867 +        return PEP_ILLEGAL_VALUE;
   3.868 +
   3.869 +    if(lock_the_mutex()){
   3.870 +        return PEP_UNKNOWN_ERROR;
   3.871 +    }
   3.872 +    
   3.873 +    if (str_to_fpr(fprstr, fpr, &length)) {
   3.874 +        unsigned insec = pgp_deletekeybyfpr(netpgp.io,
   3.875 +                                (pgp_keyring_t *)netpgp.secring, 
   3.876 +                                (const uint8_t *)fpr, length);
   3.877 +        unsigned inpub = pgp_deletekeybyfpr(netpgp.io,
   3.878 +                                (pgp_keyring_t *)netpgp.pubring, 
   3.879 +                                (const uint8_t *)fpr, length);
   3.880 +        if(!insec && !inpub){
   3.881 +            result = PEP_KEY_NOT_FOUND;
   3.882 +            goto unlock_netpgp;
   3.883 +        } else {
   3.884 +            result = PEP_STATUS_OK;
   3.885 +        }
   3.886 +    }else{
   3.887 +        result = PEP_OUT_OF_MEMORY;
   3.888 +        goto unlock_netpgp;
   3.889 +    }
   3.890 +
   3.891 +    // save rings 
   3.892 +    if (netpgp_save_pubring(&netpgp) && 
   3.893 +        netpgp_save_secring(&netpgp))
   3.894 +    {
   3.895 +        result = PEP_STATUS_OK;
   3.896 +    }else{
   3.897 +        result = PEP_UNKNOWN_ERROR;
   3.898 +    }
   3.899 +
   3.900 +unlock_netpgp:
   3.901 +    unlock_the_mutex();
   3.902 +
   3.903 +    return result;
   3.904 +}
   3.905 +
   3.906 +#define ARMOR_KEY_HEAD    "^-----BEGIN PGP (PUBLIC|PRIVATE) KEY BLOCK-----"_ENDL
   3.907 +PEP_STATUS pgp_import_keydata(
   3.908 +        PEP_SESSION session,
   3.909 +        const char *key_data, 
   3.910 +        size_t size
   3.911 +    )
   3.912 +{
   3.913 +    pgp_memory_t *mem;
   3.914 +
   3.915 +    PEP_STATUS result = PEP_STATUS_OK;
   3.916 +
   3.917 +    assert(session);
   3.918 +    assert(key_data);
   3.919 +
   3.920 +    if(!session || !key_data) 
   3.921 +        return PEP_ILLEGAL_VALUE;
   3.922 +
   3.923 +    if(lock_the_mutex()){
   3.924 +        return PEP_UNKNOWN_ERROR;
   3.925 +    }
   3.926 +
   3.927 +    mem = pgp_memory_new();
   3.928 +    if (mem == NULL) {
   3.929 +        result = PEP_OUT_OF_MEMORY;
   3.930 +        goto unlock_netpgp;
   3.931 +    }
   3.932 +    pgp_memory_add(mem, (const uint8_t*)key_data, size);
   3.933 +
   3.934 +    if (pgp_keyring_read_from_mem(netpgp.io, netpgp.pubring, netpgp.secring, 
   3.935 +                                  _armoured(key_data, size, ARMOR_KEY_HEAD),
   3.936 +                                  mem) == 0){
   3.937 +        result = PEP_ILLEGAL_VALUE;
   3.938 +    }    
   3.939 +
   3.940 +    pgp_memory_free(mem);
   3.941 +
   3.942 +    // save rings 
   3.943 +    if (netpgp_save_pubring(&netpgp) && 
   3.944 +        netpgp_save_secring(&netpgp))
   3.945 +    {
   3.946 +        result = PEP_STATUS_OK;
   3.947 +    }else{
   3.948 +        result = PEP_UNKNOWN_ERROR;
   3.949 +    }
   3.950 +
   3.951 +unlock_netpgp:
   3.952 +    unlock_the_mutex();
   3.953 +
   3.954 +    return result;
   3.955 +}
   3.956 +
   3.957 +static PEP_STATUS _export_keydata(
   3.958 +    pgp_key_t *key,
   3.959 +    char **buffer,
   3.960 +    size_t *buflen
   3.961 +    )
   3.962 +{
   3.963 +    PEP_STATUS result;
   3.964 +	pgp_output_t *output;
   3.965 +    pgp_memory_t *mem;
   3.966 +	pgp_setup_memory_write(&output, &mem, 128);
   3.967 +
   3.968 +    if (mem == NULL || output == NULL) {
   3.969 +        return PEP_ILLEGAL_VALUE;
   3.970 +    }
   3.971 +
   3.972 +    if (!pgp_write_xfer_key(output, key, 1)) {
   3.973 +        result = PEP_UNKNOWN_ERROR;
   3.974 +        goto free_mem;
   3.975 +    }
   3.976 +
   3.977 +    *buffer = NULL;
   3.978 +    *buflen = pgp_mem_len(mem);
   3.979 +
   3.980 +    // Allocate transferable buffer
   3.981 +    *buffer = malloc(*buflen + 1);
   3.982 +    assert(*buffer);
   3.983 +    if (*buffer == NULL) {
   3.984 +        result = PEP_OUT_OF_MEMORY;
   3.985 +        goto free_mem;
   3.986 +    }
   3.987 +
   3.988 +    memcpy(*buffer, pgp_mem_data(mem), *buflen);
   3.989 +    (*buffer)[*buflen] = 0; // safeguard for naive users
   3.990 +
   3.991 +    return PEP_STATUS_OK;
   3.992 +
   3.993 +free_mem :
   3.994 +	pgp_teardown_memory_write(output, mem);
   3.995 +
   3.996 +    return result;
   3.997 +}
   3.998 +
   3.999 +PEP_STATUS pgp_export_keydata(
  3.1000 +    PEP_SESSION session, const char *fprstr, char **key_data, size_t *size
  3.1001 +    )
  3.1002 +{
  3.1003 +    pgp_key_t *key;
  3.1004 +    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  3.1005 +    size_t fprlen;
  3.1006 +
  3.1007 +    PEP_STATUS result;
  3.1008 +    char *buffer;
  3.1009 +    size_t buflen;
  3.1010 +
  3.1011 +    assert(session);
  3.1012 +    assert(fprstr);
  3.1013 +    assert(key_data);
  3.1014 +    assert(size);
  3.1015 +
  3.1016 +    if (!session || !fprstr || !key_data || !size)
  3.1017 +        return PEP_ILLEGAL_VALUE;
  3.1018 +
  3.1019 +    if(lock_the_mutex()){
  3.1020 +        return PEP_UNKNOWN_ERROR;
  3.1021 +    }
  3.1022 +
  3.1023 +    if (str_to_fpr(fprstr, fpr, &fprlen)) {
  3.1024 +        unsigned from = 0;
  3.1025 +
  3.1026 +        if ((key = (pgp_key_t *)pgp_getkeybyfpr(netpgp.io, netpgp.pubring,
  3.1027 +                                                fpr, fprlen, &from,
  3.1028 +                                                NULL,0,0)) == NULL) {
  3.1029 +            result = PEP_KEY_NOT_FOUND;
  3.1030 +            goto unlock_netpgp;
  3.1031 +        }
  3.1032 +    }else{
  3.1033 +        result = PEP_OUT_OF_MEMORY;
  3.1034 +        goto unlock_netpgp;
  3.1035 +    }
  3.1036 +    
  3.1037 +    result = _export_keydata(key, &buffer, &buflen);
  3.1038 +    
  3.1039 +    if(result == PEP_STATUS_OK)
  3.1040 +    {
  3.1041 +        *key_data = buffer;
  3.1042 +        *size = buflen;
  3.1043 +        result = PEP_STATUS_OK;
  3.1044 +    }
  3.1045 +
  3.1046 +unlock_netpgp:
  3.1047 +    unlock_the_mutex();
  3.1048 +
  3.1049 +    return result;
  3.1050 +}
  3.1051 +
  3.1052 +struct HKP_answer {
  3.1053 +  char *memory;
  3.1054 +  size_t size;
  3.1055 +};
  3.1056 + 
  3.1057 +static size_t
  3.1058 +HKPAnswerWriter(void *contents, size_t size, size_t nmemb, void *userp)
  3.1059 +{
  3.1060 +  size_t realsize = size * nmemb;
  3.1061 +  struct HKP_answer *mem = (struct HKP_answer *)userp;
  3.1062 + 
  3.1063 +  mem->memory = realloc(mem->memory, mem->size + realsize + 1);
  3.1064 +  if(mem->memory == NULL) {
  3.1065 +    mem->size = 0;
  3.1066 +    return 0;
  3.1067 +  }
  3.1068 + 
  3.1069 +  memcpy(&(mem->memory[mem->size]), contents, realsize);
  3.1070 +  mem->size += realsize;
  3.1071 +  mem->memory[mem->size] = 0;
  3.1072 + 
  3.1073 +  return realsize;
  3.1074 +}
  3.1075 +
  3.1076 +#define HKP_SERVER "http://keys.gnupg.net:11371"
  3.1077 +// #define HKP_SERVER "http://127.0.0.1:11371"
  3.1078 +
  3.1079 +PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
  3.1080 +{
  3.1081 +    static const char *ks_cmd = HKP_SERVER
  3.1082 +                                "/pks/lookup?"
  3.1083 +                                "op=get&options=mr&exact=on&"
  3.1084 +                                "search=";
  3.1085 +    char *encoded_pattern;
  3.1086 +    char *request = NULL;
  3.1087 +    struct HKP_answer answer;
  3.1088 +    CURLcode curlres;
  3.1089 +       
  3.1090 +    PEP_STATUS result;
  3.1091 +
  3.1092 +    CURL *curl;
  3.1093 +
  3.1094 +    assert(session);
  3.1095 +    assert(pattern);
  3.1096 +
  3.1097 +    if (!session || !pattern )
  3.1098 +        return PEP_ILLEGAL_VALUE;
  3.1099 +
  3.1100 +    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  3.1101 +        return PEP_UNKNOWN_ERROR;
  3.1102 +    }
  3.1103 +
  3.1104 +    result = curl_get_ctx(&curl);
  3.1105 +    if(result != PEP_STATUS_OK){
  3.1106 +        goto unlock_curl;
  3.1107 +    }
  3.1108 +
  3.1109 +    encoded_pattern = curl_easy_escape(curl, (char*)pattern, 0);
  3.1110 +    if(!encoded_pattern){
  3.1111 +        result = PEP_OUT_OF_MEMORY;
  3.1112 +        goto release_curl_ctx;
  3.1113 +    }
  3.1114 +
  3.1115 +    if((request = malloc(strlen(ks_cmd) + strlen(encoded_pattern) + 1))==NULL){
  3.1116 +        result = PEP_OUT_OF_MEMORY;
  3.1117 +        goto free_encoded_pattern;
  3.1118 +    }
  3.1119 +
  3.1120 +    //(*stpcpy(stpcpy(request, ks_cmd), encoded_pattern)) = '\0';
  3.1121 +    stpcpy(stpcpy(request, ks_cmd), encoded_pattern);
  3.1122 +
  3.1123 +    curl_easy_setopt(curl, CURLOPT_URL,request);
  3.1124 +
  3.1125 +    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HKPAnswerWriter);
  3.1126 +
  3.1127 +    answer.memory = NULL;
  3.1128 +    answer.size = 0;
  3.1129 +    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&answer);
  3.1130 +
  3.1131 +    curlres = curl_easy_perform(curl);
  3.1132 +    if(curlres != CURLE_OK) {
  3.1133 +        result = PEP_GET_KEY_FAILED;
  3.1134 +        goto free_request;
  3.1135 +    }
  3.1136 +
  3.1137 +    if(!answer.memory || !answer.size) {
  3.1138 +        result = PEP_OUT_OF_MEMORY;
  3.1139 +        goto free_request;
  3.1140 +    }
  3.1141 +
  3.1142 +    result = pgp_import_keydata(session, 
  3.1143 +                                answer.memory, 
  3.1144 +                                answer.size);
  3.1145 +
  3.1146 +free_answer:
  3.1147 +    free(answer.memory);
  3.1148 +free_request:
  3.1149 +    free(request);
  3.1150 +free_encoded_pattern:
  3.1151 +    curl_free(encoded_pattern);
  3.1152 +release_curl_ctx:
  3.1153 +    curl_release_ctx(&curl);
  3.1154 +unlock_curl:
  3.1155 +    pthread_mutex_unlock(&session->ctx.curl_mutex);
  3.1156 +
  3.1157 +    return result;
  3.1158 +}
  3.1159 +
  3.1160 +typedef PEP_STATUS (*find_key_cb_t)(void*, pgp_key_t *);
  3.1161 +
  3.1162 +static PEP_STATUS find_keys_do(
  3.1163 +        const char *pattern, find_key_cb_t cb, void* cb_arg)
  3.1164 +{
  3.1165 +    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  3.1166 +    size_t length;
  3.1167 +    pgp_key_t *key;
  3.1168 +
  3.1169 +    PEP_STATUS result;
  3.1170 +
  3.1171 +    // Try find a fingerprint in pattern
  3.1172 +    if (str_to_fpr(pattern, fpr, &length)) {
  3.1173 +        unsigned from = 0;
  3.1174 +
  3.1175 +
  3.1176 +        // Only one fingerprint can match
  3.1177 +        if ((key = (pgp_key_t *)pgp_getkeybyfpr(
  3.1178 +                        netpgp.io,
  3.1179 +                        (pgp_keyring_t *)netpgp.pubring, 
  3.1180 +                        (const uint8_t *)fpr, length,
  3.1181 +                        &from,
  3.1182 +                        NULL, 0, 0)) == NULL) {
  3.1183 +
  3.1184 +            return PEP_KEY_NOT_FOUND;
  3.1185 +        }
  3.1186 +
  3.1187 +        result = cb(cb_arg, key);
  3.1188 +
  3.1189 +    } else {
  3.1190 +        // Search by name for pattern. Can match many.
  3.1191 +        unsigned from = 0;
  3.1192 +        result = PEP_KEY_NOT_FOUND;
  3.1193 +        while((key = (pgp_key_t *)pgp_getnextkeybyname(
  3.1194 +                        netpgp.io,
  3.1195 +                        (pgp_keyring_t *)netpgp.pubring, 
  3.1196 +			            (const char *)pattern,
  3.1197 +                        &from)) != NULL) {
  3.1198 +
  3.1199 +            result = cb(cb_arg, key);
  3.1200 +            if (result != PEP_STATUS_OK)
  3.1201 +                break;
  3.1202 +
  3.1203 +            from++;
  3.1204 +        }
  3.1205 +    }
  3.1206 +
  3.1207 +    return result;
  3.1208 +}
  3.1209 +
  3.1210 +static PEP_STATUS add_key_fpr_to_stringlist(void *arg, pgp_key_t *key)
  3.1211 +{
  3.1212 +    stringlist_t **keylist = arg;
  3.1213 +    char *newfprstr = NULL;
  3.1214 +
  3.1215 +    fpr_to_str(&newfprstr,
  3.1216 +               key->pubkeyfpr.fingerprint,
  3.1217 +               key->pubkeyfpr.length);
  3.1218 +
  3.1219 +    if (newfprstr == NULL) {
  3.1220 +        return PEP_OUT_OF_MEMORY;
  3.1221 +    } else { 
  3.1222 +
  3.1223 +        *keylist = stringlist_add(*keylist, newfprstr);
  3.1224 +        free(newfprstr);
  3.1225 +        if (*keylist == NULL) {
  3.1226 +            return PEP_OUT_OF_MEMORY;
  3.1227 +        }
  3.1228 +    }
  3.1229 +    return PEP_STATUS_OK;
  3.1230 +}
  3.1231 +
  3.1232 +PEP_STATUS pgp_find_keys(
  3.1233 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist
  3.1234 +    )
  3.1235 +{
  3.1236 +    stringlist_t *_keylist, *_k;
  3.1237 +
  3.1238 +    PEP_STATUS result;
  3.1239 +
  3.1240 +    assert(session);
  3.1241 +    assert(pattern);
  3.1242 +    assert(keylist);
  3.1243 +
  3.1244 +    if (!session || !pattern || !keylist )
  3.1245 +    {
  3.1246 +        return PEP_ILLEGAL_VALUE;
  3.1247 +    }
  3.1248 +
  3.1249 +    if (lock_the_mutex())
  3.1250 +    {
  3.1251 +        return PEP_UNKNOWN_ERROR;
  3.1252 +    }
  3.1253 +
  3.1254 +    *keylist = NULL;
  3.1255 +    _keylist = new_stringlist(NULL);
  3.1256 +    if (_keylist == NULL) {
  3.1257 +        result = PEP_OUT_OF_MEMORY;
  3.1258 +        goto unlock_netpgp;
  3.1259 +    }
  3.1260 +    _k = _keylist;
  3.1261 +
  3.1262 +    result = find_keys_do(pattern, &add_key_fpr_to_stringlist, &_k);
  3.1263 +
  3.1264 +    if (result == PEP_STATUS_OK) {
  3.1265 +        *keylist = _keylist;
  3.1266 +        // Transfer ownership, no free
  3.1267 +        goto unlock_netpgp;
  3.1268 +    }
  3.1269 +
  3.1270 +free_keylist:
  3.1271 +    free_stringlist(_keylist);
  3.1272 +
  3.1273 +unlock_netpgp:
  3.1274 +    unlock_the_mutex();
  3.1275 +
  3.1276 +    return result;
  3.1277 +}
  3.1278 +
  3.1279 +#define HKP_REQ_PREFIX "keytext="
  3.1280 +#define HKP_REQ_PREFIX_LEN 8
  3.1281 +
  3.1282 +static PEP_STATUS send_key_cb(void *arg, pgp_key_t *key)
  3.1283 +{
  3.1284 +    char *buffer = NULL;
  3.1285 +    size_t buflen = 0;
  3.1286 +    PEP_STATUS result;
  3.1287 +    stringlist_t *encoded_keys;
  3.1288 +    encoded_keys = (stringlist_t*)arg;
  3.1289 +
  3.1290 +    result = _export_keydata(key, &buffer, &buflen);
  3.1291 +    
  3.1292 +    if(result == PEP_STATUS_OK){
  3.1293 +        char *encoded_key = curl_escape(buffer, (int)buflen);
  3.1294 +        if(!encoded_key){
  3.1295 +            result = PEP_OUT_OF_MEMORY;
  3.1296 +            goto free_buffer;
  3.1297 +        }
  3.1298 +        size_t encoded_key_len = strlen(encoded_key);
  3.1299 +
  3.1300 +        char *request = calloc(1, HKP_REQ_PREFIX_LEN + encoded_key_len + 1);
  3.1301 +        if(!request){
  3.1302 +            result = PEP_OUT_OF_MEMORY;
  3.1303 +            goto free_encoded_key;
  3.1304 +        }
  3.1305 +        
  3.1306 +        memcpy(request, HKP_REQ_PREFIX, HKP_REQ_PREFIX_LEN);
  3.1307 +        memcpy(request + HKP_REQ_PREFIX_LEN, encoded_key, encoded_key_len);
  3.1308 +        request[HKP_REQ_PREFIX_LEN + encoded_key_len] = '\0';
  3.1309 +
  3.1310 +        if(!stringlist_add(encoded_keys, request)){
  3.1311 +            free(request);
  3.1312 +            result = PEP_OUT_OF_MEMORY;
  3.1313 +        }
  3.1314 +
  3.1315 +        free(request);
  3.1316 +
  3.1317 +free_encoded_key:
  3.1318 +        curl_free(encoded_key);
  3.1319 +
  3.1320 +free_buffer:        
  3.1321 +        free(buffer);
  3.1322 +    }
  3.1323 +
  3.1324 +    return result;
  3.1325 +}
  3.1326 +
  3.1327 +PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
  3.1328 +{
  3.1329 +    static const char *ks_cmd = HKP_SERVER "/pks/add";
  3.1330 +
  3.1331 +    PEP_STATUS result;
  3.1332 +    CURL *curl = NULL;
  3.1333 +
  3.1334 +    assert(session);
  3.1335 +    assert(pattern);
  3.1336 +
  3.1337 +    if (!session || !pattern )
  3.1338 +        return PEP_ILLEGAL_VALUE;
  3.1339 +
  3.1340 +    stringlist_t *encoded_keys = new_stringlist(NULL);
  3.1341 +    assert(encoded_keys);
  3.1342 +    if (encoded_keys == NULL) {
  3.1343 +        return PEP_OUT_OF_MEMORY;
  3.1344 +    }
  3.1345 +
  3.1346 +    if(lock_the_mutex()){
  3.1347 +        result = PEP_UNKNOWN_ERROR;
  3.1348 +        goto free_encoded_keys;
  3.1349 +    }
  3.1350 +
  3.1351 +    result = find_keys_do(pattern, &send_key_cb, (void*)encoded_keys);
  3.1352 +
  3.1353 +    unlock_the_mutex();
  3.1354 +
  3.1355 +    if(result != PEP_STATUS_OK){
  3.1356 +        goto free_encoded_keys;
  3.1357 +    }
  3.1358 +
  3.1359 +    if(pthread_mutex_lock(&session->ctx.curl_mutex)){
  3.1360 +        result = PEP_UNKNOWN_ERROR;
  3.1361 +        goto free_encoded_keys;
  3.1362 +    }
  3.1363 +
  3.1364 +    result = curl_get_ctx(&curl);
  3.1365 +    if(result != PEP_STATUS_OK){
  3.1366 +        goto unlock_curl;
  3.1367 +    }
  3.1368 +
  3.1369 +    if(result == PEP_STATUS_OK){
  3.1370 +        CURLcode curlres;
  3.1371 +
  3.1372 +        for (const stringlist_t *post = encoded_keys; post != NULL; post = post->next) {
  3.1373 +            assert(post->value);
  3.1374 +
  3.1375 +            curl_easy_setopt(curl, CURLOPT_URL, ks_cmd);
  3.1376 +            curl_easy_setopt(curl, CURLOPT_POST, 1L);
  3.1377 +            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post->value);
  3.1378 +            curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
  3.1379 +
  3.1380 +            // Uncomment if debugging
  3.1381 +            // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
  3.1382 +
  3.1383 +            curlres = curl_easy_perform(curl);
  3.1384 +
  3.1385 +            if(curlres != CURLE_OK) {
  3.1386 +
  3.1387 +                result = PEP_CANNOT_SEND_KEY;
  3.1388 +                goto release_curl_ctx;
  3.1389 +            }
  3.1390 +        }
  3.1391 +    }
  3.1392 +
  3.1393 +release_curl_ctx:
  3.1394 +    curl_release_ctx(&curl);
  3.1395 +unlock_curl:
  3.1396 +    pthread_mutex_unlock(&session->ctx.curl_mutex);
  3.1397 +free_encoded_keys:
  3.1398 +    free_stringlist(encoded_keys);
  3.1399 +
  3.1400 +    return result;
  3.1401 +}
  3.1402 +
  3.1403 +
  3.1404 +PEP_STATUS pgp_get_key_rating(
  3.1405 +    PEP_SESSION session,
  3.1406 +    const char *fprstr,
  3.1407 +    PEP_comm_type *comm_type
  3.1408 +    )
  3.1409 +{
  3.1410 +    pgp_key_t *key;
  3.1411 +    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  3.1412 +    unsigned from = 0;
  3.1413 +    size_t length;
  3.1414 +
  3.1415 +
  3.1416 +    PEP_STATUS status = PEP_STATUS_OK;
  3.1417 +
  3.1418 +    assert(session);
  3.1419 +    assert(fprstr);
  3.1420 +    assert(comm_type);
  3.1421 +
  3.1422 +    if (!session || !fprstr || !comm_type )
  3.1423 +        return PEP_ILLEGAL_VALUE;
  3.1424 +
  3.1425 +    *comm_type = PEP_ct_unknown;
  3.1426 +
  3.1427 +    if(lock_the_mutex()){
  3.1428 +        return PEP_UNKNOWN_ERROR;
  3.1429 +    }
  3.1430 +
  3.1431 +    if (!str_to_fpr(fprstr, fpr, &length)) {
  3.1432 +        status = PEP_ILLEGAL_VALUE;
  3.1433 +        goto unlock_netpgp;
  3.1434 +    }
  3.1435 +        
  3.1436 +    key = pgp_getkeybyfpr(
  3.1437 +           netpgp.io,
  3.1438 +           netpgp.pubring,
  3.1439 +           fpr, length, &from, NULL,0,0);
  3.1440 +
  3.1441 +    if(key == NULL)
  3.1442 +    {
  3.1443 +        status = PEP_KEY_NOT_FOUND;
  3.1444 +        goto unlock_netpgp;
  3.1445 +    }
  3.1446 +
  3.1447 +    switch(pgp_key_get_rating(key)){
  3.1448 +	case PGP_VALID:
  3.1449 +        *comm_type = PEP_ct_OpenPGP_unconfirmed;
  3.1450 +        break;
  3.1451 +    case PGP_WEAK:
  3.1452 +        *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
  3.1453 +        break;
  3.1454 +    case PGP_TOOSHORT:
  3.1455 +        *comm_type = PEP_ct_key_too_short;
  3.1456 +        break;
  3.1457 +	case PGP_INVALID:
  3.1458 +        *comm_type = PEP_ct_key_b0rken;
  3.1459 +        break;
  3.1460 +	case PGP_EXPIRED:
  3.1461 +        *comm_type = PEP_ct_key_expired;
  3.1462 +        break;
  3.1463 +    case PGP_REVOKED:
  3.1464 +        *comm_type = PEP_ct_key_revoked;
  3.1465 +        break;
  3.1466 +    default:
  3.1467 +        break;
  3.1468 +    }
  3.1469 +
  3.1470 +unlock_netpgp:
  3.1471 +    unlock_the_mutex();
  3.1472 +
  3.1473 +    return status;
  3.1474 +}
  3.1475 +
  3.1476 +PEP_STATUS pgp_renew_key(
  3.1477 +        PEP_SESSION session,
  3.1478 +        const char *fprstr,
  3.1479 +        const timestamp *ts
  3.1480 +    )
  3.1481 +{
  3.1482 +    pgp_key_t *pkey;
  3.1483 +    pgp_key_t *skey;
  3.1484 +    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  3.1485 +    size_t length;
  3.1486 +    unsigned from = 0;
  3.1487 +    time_t duration;
  3.1488 +    const uint8_t *primid;
  3.1489 +
  3.1490 +    PEP_STATUS status = PEP_STATUS_OK;
  3.1491 +
  3.1492 +    assert(session);
  3.1493 +    assert(fprstr);
  3.1494 +
  3.1495 +    if (!session || !fprstr )
  3.1496 +        return PEP_ILLEGAL_VALUE;
  3.1497 +
  3.1498 +    if(ts)
  3.1499 +    {
  3.1500 +        time_t    now, when;
  3.1501 +        now = time(NULL);
  3.1502 +        when = mktime((struct tm*)ts);
  3.1503 +        if(now && when && when > now){
  3.1504 +            duration = when - now;
  3.1505 +        }else{
  3.1506 +            return PEP_ILLEGAL_VALUE;
  3.1507 +        }
  3.1508 +    }else{
  3.1509 +        /* Default 1 year from now */
  3.1510 +        duration = 365*24*3600;
  3.1511 +    }
  3.1512 +
  3.1513 +    if(lock_the_mutex()){
  3.1514 +        return PEP_UNKNOWN_ERROR;
  3.1515 +    }
  3.1516 +
  3.1517 +    
  3.1518 +    if (!str_to_fpr(fprstr, fpr, &length)) {
  3.1519 +        status = PEP_ILLEGAL_VALUE;
  3.1520 +        goto unlock_netpgp;
  3.1521 +    }
  3.1522 +    
  3.1523 +    pkey = pgp_getkeybyfpr(
  3.1524 +                          netpgp.io,
  3.1525 +                          netpgp.pubring,
  3.1526 +                          fpr, length, &from, NULL,
  3.1527 +                          1, 0); /* reject revoked, accept expired */
  3.1528 +
  3.1529 +    if(pkey == NULL)
  3.1530 +    {
  3.1531 +        status = PEP_KEY_NOT_FOUND;
  3.1532 +        goto unlock_netpgp;
  3.1533 +    }
  3.1534 +
  3.1535 +    from = 0;
  3.1536 +    skey = pgp_getkeybyfpr(
  3.1537 +                           netpgp.io,
  3.1538 +                           netpgp.secring,
  3.1539 +                           fpr, length, &from, NULL,
  3.1540 +                           1, 0); /* reject revoked, accept expired */
  3.1541 +
  3.1542 +    if(skey == NULL)
  3.1543 +    {
  3.1544 +        status = PEP_KEY_NOT_FOUND;
  3.1545 +        goto unlock_netpgp;
  3.1546 +    }
  3.1547 +
  3.1548 +    if((primid = pgp_key_get_primary_userid(skey)) == NULL)
  3.1549 +    {
  3.1550 +        status = PEP_KEY_HAS_AMBIG_NAME;
  3.1551 +        goto unlock_netpgp;
  3.1552 +    }
  3.1553 +
  3.1554 +    // FIXME : renew in a more gentle way
  3.1555 +    if (!pgp_add_selfsigned_userid(skey, pkey, primid, duration))
  3.1556 +    {
  3.1557 +        status = PEP_CANNOT_CREATE_KEY;
  3.1558 +        goto unlock_netpgp;
  3.1559 +    }
  3.1560 +
  3.1561 +    // save rings
  3.1562 +    if (netpgp_save_pubring(&netpgp) &&
  3.1563 +        netpgp_save_secring(&netpgp))
  3.1564 +    {
  3.1565 +        status = PEP_STATUS_OK;
  3.1566 +    }else{
  3.1567 +        status = PEP_UNKNOWN_ERROR;
  3.1568 +    }
  3.1569 +    
  3.1570 +unlock_netpgp:
  3.1571 +    unlock_the_mutex();
  3.1572 +
  3.1573 +    return status;
  3.1574 +}
  3.1575 +
  3.1576 +PEP_STATUS pgp_revoke_key(
  3.1577 +        PEP_SESSION session,
  3.1578 +        const char *fprstr,
  3.1579 +        const char *reason
  3.1580 +    )
  3.1581 +{
  3.1582 +    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  3.1583 +    size_t length;
  3.1584 +    unsigned from = 0;
  3.1585 +
  3.1586 +    PEP_STATUS status = PEP_STATUS_OK;
  3.1587 +
  3.1588 +    assert(session);
  3.1589 +    assert(fprstr);
  3.1590 +
  3.1591 +    if (!session || !fprstr)
  3.1592 +        return PEP_UNKNOWN_ERROR;
  3.1593 +
  3.1594 +    if(lock_the_mutex()){
  3.1595 +        return PEP_UNKNOWN_ERROR;
  3.1596 +    }
  3.1597 +
  3.1598 +    // FIXME : deduplicate that code w/ renew
  3.1599 +    if (!str_to_fpr(fprstr, fpr, &length)) {
  3.1600 +        status = PEP_ILLEGAL_VALUE;
  3.1601 +        goto unlock_netpgp;
  3.1602 +    }
  3.1603 +    
  3.1604 +    pgp_key_t *pkey = pgp_getkeybyfpr(
  3.1605 +                           netpgp.io,
  3.1606 +                           netpgp.pubring,
  3.1607 +                           fpr, length, &from, NULL,
  3.1608 +                           1, 0); /* reject revoked, accept expired */
  3.1609 +    
  3.1610 +    if(pkey == NULL)
  3.1611 +    {
  3.1612 +        status = PEP_KEY_NOT_FOUND;
  3.1613 +        goto unlock_netpgp;
  3.1614 +    }
  3.1615 +    
  3.1616 +    from = 0;
  3.1617 +    pgp_key_t *skey = pgp_getkeybyfpr(
  3.1618 +                           netpgp.io,
  3.1619 +                           netpgp.secring,
  3.1620 +                           fpr, length, &from, NULL,
  3.1621 +                           1, 0); /* reject revoked, accept expired */
  3.1622 +    
  3.1623 +    if(skey == NULL)
  3.1624 +    {
  3.1625 +        status = PEP_KEY_NOT_FOUND;
  3.1626 +        goto unlock_netpgp;
  3.1627 +    }
  3.1628 +
  3.1629 +    pgp_key_revoke(skey, pkey,
  3.1630 +                   0, /* no reason code specified */
  3.1631 +                   reason);
  3.1632 +
  3.1633 +unlock_netpgp:
  3.1634 +    unlock_the_mutex();
  3.1635 +
  3.1636 +    return status;
  3.1637 +}
  3.1638 +
  3.1639 +PEP_STATUS pgp_key_expired(
  3.1640 +        PEP_SESSION session,
  3.1641 +        const char *fprstr,
  3.1642 +        const time_t when,
  3.1643 +        bool *expired
  3.1644 +    )
  3.1645 +{
  3.1646 +    PEP_STATUS status = PEP_STATUS_OK;
  3.1647 +    PEP_comm_type comm_type;
  3.1648 +
  3.1649 +    assert(session);
  3.1650 +    assert(fprstr);
  3.1651 +    assert(expired);
  3.1652 +
  3.1653 +    if (!session || !fprstr || !expired)
  3.1654 +        return PEP_UNKNOWN_ERROR;
  3.1655 +
  3.1656 +    // TODO : take "when" in account 
  3.1657 +
  3.1658 +    *expired = false;
  3.1659 +
  3.1660 +    status = pgp_get_key_rating(session, fprstr, &comm_type);
  3.1661 +
  3.1662 +    if (status != PEP_STATUS_OK)
  3.1663 +        return status;
  3.1664 +
  3.1665 +    if (comm_type == PEP_ct_key_expired){
  3.1666 +        *expired = true;
  3.1667 +    }
  3.1668 +
  3.1669 +    return PEP_STATUS_OK;
  3.1670 +}
  3.1671 +
  3.1672 +PEP_STATUS pgp_key_revoked(
  3.1673 +        PEP_SESSION session,
  3.1674 +        const char *fprstr,
  3.1675 +        bool *revoked
  3.1676 +    )
  3.1677 +{
  3.1678 +    PEP_STATUS status = PEP_STATUS_OK;
  3.1679 +    PEP_comm_type comm_type;
  3.1680 +    
  3.1681 +    assert(session);
  3.1682 +    assert(fprstr);
  3.1683 +    assert(revoked);
  3.1684 +    
  3.1685 +    *revoked = false;
  3.1686 +    
  3.1687 +    status = pgp_get_key_rating(session, fprstr, &comm_type);
  3.1688 +    
  3.1689 +    if (status != PEP_STATUS_OK)
  3.1690 +        return status;
  3.1691 +    
  3.1692 +    if (comm_type == PEP_ct_key_revoked){
  3.1693 +        *revoked = true;
  3.1694 +    }
  3.1695 +    
  3.1696 +    return PEP_STATUS_OK;
  3.1697 +}
  3.1698 +
  3.1699 +PEP_STATUS pgp_key_created(
  3.1700 +        PEP_SESSION session,
  3.1701 +        const char *fprstr,
  3.1702 +        time_t *created
  3.1703 +    )
  3.1704 +{
  3.1705 +    uint8_t fpr[PGP_FINGERPRINT_SIZE];
  3.1706 +    pgp_key_t *key;
  3.1707 +    size_t length;
  3.1708 +    unsigned from = 0;
  3.1709 +
  3.1710 +    PEP_STATUS status = PEP_STATUS_OK;
  3.1711 +
  3.1712 +    assert(session);
  3.1713 +    assert(fprstr);
  3.1714 +    assert(created);
  3.1715 +
  3.1716 +    if (!session || !fprstr || !created)
  3.1717 +        return PEP_UNKNOWN_ERROR;
  3.1718 +
  3.1719 +    *created = 0;
  3.1720 +
  3.1721 +    if(lock_the_mutex()){
  3.1722 +        return PEP_UNKNOWN_ERROR;
  3.1723 +    }
  3.1724 +
  3.1725 +    if (!str_to_fpr(fprstr, fpr, &length)) {
  3.1726 +        status = PEP_ILLEGAL_VALUE;
  3.1727 +        goto unlock_netpgp;
  3.1728 +    }
  3.1729 +        
  3.1730 +    key = pgp_getkeybyfpr(
  3.1731 +           netpgp.io,
  3.1732 +           netpgp.pubring,
  3.1733 +           fpr, length, &from, NULL,0,0);
  3.1734 +
  3.1735 +    if (key)
  3.1736 +    {
  3.1737 +        *created = (time_t) key->key.pubkey.birthtime;
  3.1738 +    }
  3.1739 +    else
  3.1740 +    {
  3.1741 +        status = PEP_KEY_NOT_FOUND;
  3.1742 +        goto unlock_netpgp;
  3.1743 +    }
  3.1744 +    
  3.1745 +
  3.1746 +
  3.1747 +unlock_netpgp:
  3.1748 +    unlock_the_mutex();
  3.1749 +
  3.1750 +    return status;
  3.1751 +}