Backed out changeset 8044e36f9ac7 keysync
authorDirk Zimmermann <dirk@pep-project.org>
Thu, 04 Aug 2016 09:32:06 +0200
branchkeysync
changeset 97343645546de1b
parent 972 8044e36f9ac7
child 976 75cbd583a894
Backed out changeset 8044e36f9ac7
build-mac/pEpEngine.xcodeproj/project.pbxproj
src/pgp_netpgp.c
src/pgp_netpgp.m
     1.1 --- a/build-mac/pEpEngine.xcodeproj/project.pbxproj	Wed Aug 03 18:56:31 2016 +0200
     1.2 +++ b/build-mac/pEpEngine.xcodeproj/project.pbxproj	Thu Aug 04 09:32:06 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.m in Sources */ = {isa = PBXBuildFile; fileRef = 64A826631B455D0800EECAF0 /* pgp_netpgp.m */; };
     1.8 +		64A826821B455D0800EECAF0 /* pgp_netpgp.c in Sources */ = {isa = PBXBuildFile; fileRef = 64A826631B455D0800EECAF0 /* pgp_netpgp.c */; };
     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.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = pgp_netpgp.m; path = ../src/pgp_netpgp.m; sourceTree = "<group>"; };
    1.17 +		64A826631B455D0800EECAF0 /* pgp_netpgp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pgp_netpgp.c; path = ../src/pgp_netpgp.c; 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.m */,
    1.26 +				64A826631B455D0800EECAF0 /* pgp_netpgp.c */,
    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.m in Sources */,
    1.35 +				64A826821B455D0800EECAF0 /* pgp_netpgp.c 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 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/pgp_netpgp.c	Thu Aug 04 09:32:06 2016 +0200
     2.3 @@ -0,0 +1,1700 @@
     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 --- a/src/pgp_netpgp.m	Wed Aug 03 18:56:31 2016 +0200
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,1748 +0,0 @@
     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 -}