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