diff --git a/pEpEngine.vcxproj b/pEpEngine.vcxproj
index edeadd28..52183508 100644
--- a/pEpEngine.vcxproj
+++ b/pEpEngine.vcxproj
@@ -84,6 +84,7 @@
+
@@ -92,6 +93,9 @@
+
+
+
diff --git a/pEpEngine.vcxproj.filters b/pEpEngine.vcxproj.filters
index a8a6c0b7..4a0dafae 100644
--- a/pEpEngine.vcxproj.filters
+++ b/pEpEngine.vcxproj.filters
@@ -33,6 +33,9 @@
Quelldateien
+
+ Quelldateien
+
@@ -53,5 +56,14 @@
Headerdateien
+
+ Headerdateien
+
+
+ Headerdateien
+
+
+ Headerdateien
+
\ No newline at end of file
diff --git a/src/cryptotech.c b/src/cryptotech.c
index e2f9f8c6..1857c62a 100644
--- a/src/cryptotech.c
+++ b/src/cryptotech.c
@@ -1,5 +1,11 @@
#include "cryptotech.h"
+#ifdef NO_GPG
+#include "pgp_netpgp.h"
+#else
+#include "pgp_gpg.h"
+#endif
+
#include
#include
#include
@@ -10,11 +16,23 @@ PEP_STATUS init_cryptotech(PEP_cryptotech_t *cryptotech)
memset(cryptotech, 0, sizeof(PEP_cryptotech_t) * PEP_crypt__count);
cryptotech[0].id = PEP_crypt_none;
+ cryptotech[0].unconfirmed_comm_type = PEP_ct_no_encryption;
+ cryptotech[0].confirmed_comm_type = PEP_ct_no_encryption;
cryptotech[1].id = PEP_crypt_OpenPGP;
- cryptotech[1].decrypt_and_verify = decrypt_and_verify;
- cryptotech[1].encrypt_and_sign = encrypt_and_sign;
- cryptotech[1].verify_text = verify_text;
+ cryptotech[1].unconfirmed_comm_type = PEP_ct_OpenPGP_unconfirmed;
+ cryptotech[1].confirmed_comm_type = PEP_ct_OpenPGP;
+ cryptotech[1].decrypt_and_verify = pgp_decrypt_and_verify;
+ cryptotech[1].encrypt_and_sign = pgp_encrypt_and_sign;
+ cryptotech[1].verify_text = pgp_verify_text;
+ cryptotech[1].delete_keypair = pgp_delete_keypair;
+ cryptotech[1].export_key = pgp_export_key;
+ cryptotech[1].find_keys = pgp_find_keys;
+ cryptotech[1].generate_keypair = pgp_generate_keypair;
+ cryptotech[1].get_key_rating = pgp_get_key_rating;
+ cryptotech[1].import_key = pgp_import_key;
+ cryptotech[1].recv_key = pgp_recv_key;
+ cryptotech[1].send_key = pgp_send_key;
return PEP_STATUS_OK;
}
diff --git a/src/cryptotech.h b/src/cryptotech.h
index 2201a618..65916098 100644
--- a/src/cryptotech.h
+++ b/src/cryptotech.h
@@ -4,10 +4,10 @@
typedef enum _PEP_cryptotech {
PEP_crypt_none = 0,
- PEP_crypt_OpenPGP = 0x2f,
-// PEP_ctypt_PEP = 0x6f,
-// PEP_crypt_SMIME = 0x10,
-// PEP_crypt_CMS = 0x20,
+ PEP_crypt_OpenPGP,
+ // PEP_ctypt_PEP,
+ // PEP_crypt_SMIME,
+ // PEP_crypt_CMS,
PEP_crypt__count
};
@@ -27,11 +27,48 @@ typedef PEP_STATUS (*encrypt_and_sign_t)(
size_t psize, char **ctext, size_t *csize
);
+typedef PEP_STATUS (*delete_keypair_t)(PEP_SESSION session, const char *fpr);
+
+typedef PEP_STATUS (*export_key_t)(
+ PEP_SESSION session, const char *fpr, char **key_data, size_t *size
+ );
+
+typedef PEP_STATUS (*find_keys_t)(
+ PEP_SESSION session, const char *pattern, stringlist_t **keylist
+ );
+
+typedef PEP_STATUS (*generate_keypair_t)(
+ PEP_SESSION session, pEp_identity *identity
+ );
+
+typedef PEP_STATUS (*get_key_rating_t)(
+ PEP_SESSION session,
+ const char *fpr,
+ PEP_comm_type *comm_type
+ );
+
+typedef PEP_STATUS (*import_key_t)(PEP_SESSION session, const char *key_data, size_t size);
+
+typedef PEP_STATUS (*recv_key_t)(PEP_SESSION session, const char *pattern);
+
+typedef PEP_STATUS (*send_key_t)(PEP_SESSION session, const char *pattern);
+
typedef struct _PEP_cryptotech_t {
uint8_t id;
+ // the following are default values; comm_type may vary with key length or b0rken crypto
+ uint8_t unconfirmed_comm_type;
+ uint8_t confirmed_comm_type;
decrypt_and_verify_t decrypt_and_verify;
verify_text_t verify_text;
encrypt_and_sign_t encrypt_and_sign;
+ delete_keypair_t delete_keypair;
+ export_key_t export_key;
+ find_keys_t find_keys;
+ generate_keypair_t generate_keypair;
+ get_key_rating_t get_key_rating;
+ import_key_t import_key;
+ recv_key_t recv_key;
+ send_key_t send_key;
} PEP_cryptotech_t;
typedef uint64_t cryptotech_mask;
diff --git a/src/gpgme.exp b/src/gpgme.exp
new file mode 100644
index 00000000..e62d1210
Binary files /dev/null and b/src/gpgme.exp differ
diff --git a/src/gpgme.lib b/src/gpgme.lib
new file mode 100644
index 00000000..23f4e701
Binary files /dev/null and b/src/gpgme.lib differ
diff --git a/src/keymanagement.c b/src/keymanagement.c
index 9a082f41..cd36fca3 100644
--- a/src/keymanagement.c
+++ b/src/keymanagement.c
@@ -257,6 +257,9 @@ DYNAMIC_API PEP_STATUS do_keymanagement(
if (status != PEP_STATUS_OK)
return status;
+ assert(retrieve_next_identity);
+ assert(management);
+
log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
while (identity = retrieve_next_identity(management)) {
diff --git a/src/pEpEngine.c b/src/pEpEngine.c
index 0da30e5b..a99eb029 100644
--- a/src/pEpEngine.c
+++ b/src/pEpEngine.c
@@ -1,216 +1,13 @@
-#define PEP_ENGINE_VERSION "0.4.0"
-
-// this is 20 safewords with 79 chars max
-#define MAX_SAFEWORDS_SPACE (20 * 80)
-
-// XML parameters string
-#define PARMS_MAX 32768
-
-// maximum busy wait time in ms
-#define BUSY_WAIT_TIME 5000
-
-// maximum line length for reading gpg.conf
-#define MAX_LINELENGTH 1024
-
-// default keyserver
-#define DEFAULT_KEYSERVER "hkp://keys.gnupg.net"
-
-#ifdef WIN32
-#include "platform_windows.h"
-#define LOCAL_DB windoze_local_db()
-#define SYSTEM_DB windoze_system_db()
-#define LIBGPGME "libgpgme-11.dll"
-#else // UNIX
-#define _POSIX_C_SOURCE 200809L
-#include
-#include "platform_unix.h"
-#define LOCAL_DB unix_local_db()
-#ifndef SYSTEM_DB
-#define SYSTEM_DB "/usr/share/pEp/system.db"
-#endif
-#ifndef LIBGPGME
-#define LIBGPGME "libgpgme-pthread.so"
-#endif
-#endif
-
-#include
-#include
-#include
-#include
-#include
-
-#ifndef NDEBUG
-#include
+#include "pEp_internal.h"
+#ifndef NO_GPG
+#include "pgp_gpg.h"
+#else
+#include "pgp_netpgp.h"
#endif
-#include
-#include "sqlite3.h"
-
-#define _EXPORT_PEP_ENGINE_DLL
-#include "pEpEngine.h"
-
-#define NOT_IMPLEMENTED assert(0)
-
-// init
-
-typedef const char * (*gpgme_check_version_t)(const char*);
-typedef gpgme_error_t (*gpgme_set_locale_t)(gpgme_ctx_t CTX, int CATEGORY,
- const char *VALUE);
-typedef gpgme_error_t (*gpgme_new_t)(gpgme_ctx_t *CTX);
-typedef void (*gpgme_release_t)(gpgme_ctx_t CTX);
-typedef gpgme_error_t (*gpgme_set_protocol_t)(gpgme_ctx_t CTX,
- gpgme_protocol_t PROTO);
-typedef void (*gpgme_set_armor_t)(gpgme_ctx_t CTX, int YES);
-
-// data
-
-typedef gpgme_error_t (*gpgme_data_new_t)(gpgme_data_t *DH);
-typedef gpgme_error_t (*gpgme_data_new_from_mem_t)(gpgme_data_t *DH,
- const char *BUFFER, size_t SIZE, int COPY);
-typedef void (*gpgme_data_release_t)(gpgme_data_t DH);
-typedef gpgme_data_type_t (*gpgme_data_identify_t)(gpgme_data_t DH);
-typedef size_t (*gpgme_data_seek_t)(gpgme_data_t DH, size_t OFFSET,
- int WHENCE);
-typedef size_t (*gpgme_data_read_t)(gpgme_data_t DH, void *BUFFER,
- size_t LENGTH);
-
-// encrypt and decrypt
-
-typedef gpgme_error_t (*gpgme_op_decrypt_t)(gpgme_ctx_t CTX,
- gpgme_data_t CIPHER, gpgme_data_t PLAIN);
-typedef gpgme_error_t (*gpgme_op_verify_t)(gpgme_ctx_t CTX, gpgme_data_t SIG,
- gpgme_data_t SIGNED_TEXT, gpgme_data_t PLAIN);
-typedef gpgme_error_t (*gpgme_op_decrypt_verify_t)(gpgme_ctx_t CTX,
- gpgme_data_t CIPHER, gpgme_data_t PLAIN);
-typedef gpgme_decrypt_result_t (*gpgme_op_decrypt_result_t)(gpgme_ctx_t CTX);
-typedef gpgme_error_t (*gpgme_op_encrypt_sign_t)(gpgme_ctx_t CTX,
- gpgme_key_t RECP[], gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
- gpgme_data_t CIPHER);
-typedef gpgme_verify_result_t (*gpgme_op_verify_result_t)(gpgme_ctx_t CTX);
-typedef void (*gpgme_signers_clear_t)(gpgme_ctx_t CTX);
-typedef gpgme_error_t (*gpgme_signers_add_t)(gpgme_ctx_t CTX, const gpgme_key_t KEY);
-
-// keys
-
-typedef gpgme_error_t (*gpgme_get_key_t)(gpgme_ctx_t CTX, const char *FPR,
- gpgme_key_t *R_KEY, int SECRET);
-typedef gpgme_error_t (*gpgme_op_genkey_t)(gpgme_ctx_t CTX, const char *PARMS,
- gpgme_data_t PUBLIC, gpgme_data_t SECRET);
-typedef gpgme_genkey_result_t (*gpgme_op_genkey_result_t)(gpgme_ctx_t CTX);
-typedef gpgme_error_t (*gpgme_op_delete_t)(gpgme_ctx_t CTX,
- const gpgme_key_t KEY, int ALLOW_SECRET);
-typedef gpgme_error_t (*gpgme_op_import_t)(gpgme_ctx_t CTX,
- gpgme_data_t KEYDATA);
-typedef gpgme_error_t (*gpgme_op_export_t)(gpgme_ctx_t CTX,
- const char *PATTERN, gpgme_export_mode_t MODE, gpgme_data_t KEYDATA);
-typedef gpgme_error_t (*gpgme_set_keylist_mode_t)(gpgme_ctx_t CTX,
- gpgme_keylist_mode_t MODE);
-typedef gpgme_keylist_mode_t (*gpgme_get_keylist_mode_t)(gpgme_ctx_t CTX);
-typedef gpgme_error_t (*gpgme_op_keylist_start_t)(gpgme_ctx_t CTX,
- const char *PATTERN, int SECRET_ONLY);
-typedef gpgme_error_t (*gpgme_op_keylist_next_t)(gpgme_ctx_t CTX,
- gpgme_key_t *R_KEY);
-typedef gpgme_error_t (*gpgme_op_keylist_end_t)(gpgme_ctx_t CTX);
-typedef gpgme_error_t (*gpgme_op_import_keys_t)(gpgme_ctx_t CTX,
- gpgme_key_t *KEYS);
-typedef void (*gpgme_key_ref_t)(gpgme_key_t KEY);
-typedef void (*gpgme_key_unref_t)(gpgme_key_t KEY);
-
-typedef struct {
- const char *version;
- const char *passphrase;
- void * gpgme;
- gpgme_ctx_t ctx;
-
- sqlite3 *db;
- sqlite3 *system_db;
-
- sqlite3_stmt *log;
- sqlite3_stmt *safeword;
- sqlite3_stmt *get_identity;
- sqlite3_stmt *set_person;
- sqlite3_stmt *set_pgp_keypair;
- sqlite3_stmt *set_identity;
- sqlite3_stmt *set_trust;
- sqlite3_stmt *get_trust;
-
- gpgme_check_version_t gpgme_check;
- gpgme_set_locale_t gpgme_set_locale;
- gpgme_new_t gpgme_new;
- gpgme_release_t gpgme_release;
- gpgme_set_protocol_t gpgme_set_protocol;
- gpgme_set_armor_t gpgme_set_armor;
-
- gpgme_data_new_t gpgme_data_new;
- gpgme_data_new_from_mem_t gpgme_data_new_from_mem;
- gpgme_data_release_t gpgme_data_release;
- gpgme_data_identify_t gpgme_data_identify;
- gpgme_data_seek_t gpgme_data_seek;
- gpgme_data_read_t gpgme_data_read;
-
- gpgme_op_decrypt_t gpgme_op_decrypt;
- gpgme_op_verify_t gpgme_op_verify;
- gpgme_op_decrypt_verify_t gpgme_op_decrypt_verify;
- gpgme_op_decrypt_result_t gpgme_op_decrypt_result;
- gpgme_op_encrypt_sign_t gpgme_op_encrypt_sign;
- gpgme_op_verify_result_t gpgme_op_verify_result;
- gpgme_signers_clear_t gpgme_signers_clear;
- gpgme_signers_add_t gpgme_signers_add;
-
- gpgme_get_key_t gpgme_get_key;
- gpgme_op_genkey_t gpgme_op_genkey;
- gpgme_op_genkey_result_t gpgme_op_genkey_result;
- gpgme_op_delete_t gpgme_op_delete;
- gpgme_op_import_t gpgme_op_import;
- gpgme_op_export_t gpgme_op_export;
- gpgme_set_keylist_mode_t gpgme_set_keylist_mode;
- gpgme_get_keylist_mode_t gpgme_get_keylist_mode;
- gpgme_op_keylist_start_t gpgme_op_keylist_start;
- gpgme_op_keylist_next_t gpgme_op_keylist_next;
- gpgme_op_keylist_end_t gpgme_op_keylist_end;
- gpgme_op_import_keys_t gpgme_op_import_keys;
- gpgme_key_ref_t gpgme_key_ref;
- gpgme_key_unref_t gpgme_key_unref;
-} pEpSession;
-
-static bool ensure_keyserver()
-{
- static char buf[MAX_LINELENGTH];
- int n;
- FILE *f = fopen(gpg_conf(), "r");
-
- if (f != NULL) {
- while (!feof(f)) {
- char * s = fgets(buf, MAX_LINELENGTH, f);
- if (s && !feof(f)) {
- char * t = strtok(s, " ");
- if (t && strcmp(t, "keyserver") == 0)
- {
- fclose(f);
- return true;
- }
- }
- }
- f = freopen(gpg_conf(), "a", f);
- }
- else {
- f = fopen(gpg_conf(), "w");
- }
-
- assert(f);
- if (f == NULL)
- return false;
-
- n = fprintf(f, "keyserver %s\n", DEFAULT_KEYSERVER);
- assert(n >= 0);
- fclose(f);
-
- return true;
-}
-
DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
{
- gpgme_error_t gpgme_error;
+ PEP_STATUS status_result;
int int_result;
const char *sql_log;
const char *sql_safeword;
@@ -221,8 +18,6 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
const char *sql_set_trust;
const char *sql_get_trust;
- bool bResult;
-
assert(sqlite3_threadsafe());
if (!sqlite3_threadsafe())
return PEP_INIT_SQLITE3_WITHOUT_MUTEX;
@@ -237,195 +32,16 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
_session->version = PEP_ENGINE_VERSION;
- bResult = ensure_keyserver();
- assert(bResult);
-
- // to do: implement something useful
- _session->passphrase = "";
-
- _session->gpgme = dlopen(LIBGPGME, RTLD_LAZY);
- if (_session->gpgme == NULL) {
- free(_session);
- return PEP_INIT_CANNOT_LOAD_GPGME;
- }
-
- _session->gpgme_set_locale
- = (gpgme_set_locale_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_set_locale");
- assert(_session->gpgme_set_locale);
-
- _session->gpgme_check
- = (gpgme_check_version_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_check_version");
- assert(_session->gpgme_check);
-
- _session->gpgme_new
- = (gpgme_new_t) (intptr_t) dlsym(_session->gpgme, "gpgme_new");
- assert(_session->gpgme_new);
-
- _session->gpgme_release
- = (gpgme_release_t) (intptr_t) dlsym(_session->gpgme, "gpgme_release");
- assert(_session->gpgme_release);
-
- _session->gpgme_set_protocol
- = (gpgme_set_protocol_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_set_protocol");
- assert(_session->gpgme_set_protocol);
-
- _session->gpgme_set_armor
- = (gpgme_set_armor_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_set_armor");
- assert(_session->gpgme_set_armor);
-
- _session->gpgme_data_new
- = (gpgme_data_new_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_data_new");
- assert(_session->gpgme_data_new);
-
- _session->gpgme_data_new_from_mem
- = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_data_new_from_mem");
- assert(_session->gpgme_data_new_from_mem);
-
- _session->gpgme_data_release
- = (gpgme_data_release_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_data_release");
- assert(_session->gpgme_data_release);
-
- _session->gpgme_data_identify
- = (gpgme_data_identify_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_data_identify");
- assert(_session->gpgme_data_identify);
-
- _session->gpgme_data_seek
- = (gpgme_data_seek_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_data_seek");
- assert(_session->gpgme_data_seek);
-
- _session->gpgme_data_read
- = (gpgme_data_read_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_data_read");
- assert(_session->gpgme_data_read);
-
- _session->gpgme_op_decrypt
- = (gpgme_op_decrypt_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_decrypt");
- assert(_session->gpgme_op_decrypt);
-
- _session->gpgme_op_verify
- = (gpgme_op_verify_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_verify");
- assert(_session->gpgme_op_verify);
-
- _session->gpgme_op_decrypt_verify
- = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_decrypt_verify");
- assert(_session->gpgme_op_decrypt_verify);
-
- _session->gpgme_op_decrypt_result
- = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_decrypt_result");
- assert(_session->gpgme_op_decrypt_result);
-
- _session->gpgme_op_encrypt_sign
- = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_encrypt_sign");
- assert(_session->gpgme_op_encrypt_sign);
-
- _session->gpgme_op_verify_result
- = (gpgme_op_verify_result_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_verify_result");
- assert(_session->gpgme_op_verify_result);
-
- _session->gpgme_signers_clear
- = (gpgme_signers_clear_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_signers_clear");
- assert(_session->gpgme_signers_clear);
-
- _session->gpgme_signers_add
- = (gpgme_signers_add_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_signers_add");
- assert(_session->gpgme_signers_add);
-
- _session->gpgme_get_key
- = (gpgme_get_key_t) (intptr_t) dlsym(_session->gpgme, "gpgme_get_key");
- assert(_session->gpgme_get_key);
-
- _session->gpgme_op_genkey
- = (gpgme_op_genkey_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_genkey");
- assert(_session->gpgme_op_genkey);
-
- _session->gpgme_op_genkey_result
- = (gpgme_op_genkey_result_t) (intptr_t) dlsym(_session->gpgme,
- "gpgme_op_genkey_result");
- assert(_session->gpgme_op_genkey_result);
-
- _session->gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_op_delete");
- assert(_session->gpgme_op_delete);
-
- _session->gpgme_op_import = (gpgme_op_import_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_op_import");
- assert(_session->gpgme_op_import);
-
- _session->gpgme_op_export = (gpgme_op_export_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_op_export");
- assert(_session->gpgme_op_export);
-
- _session->gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_set_keylist_mode");
- assert(_session->gpgme_set_keylist_mode);
-
- _session->gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_get_keylist_mode");
- assert(_session->gpgme_get_keylist_mode);
-
- _session->gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_op_keylist_start");
- assert(_session->gpgme_op_keylist_start);
-
- _session->gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_op_keylist_next");
- assert(_session->gpgme_op_keylist_next);
-
- _session->gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_op_keylist_end");
- assert(_session->gpgme_op_keylist_end);
-
- _session->gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_op_import_keys");
- assert(_session->gpgme_op_import_keys);
-
- _session->gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_key_ref");
- assert(_session->gpgme_key_ref);
-
- _session->gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
- dlsym(_session->gpgme, "gpgme_key_unref");
- assert(_session->gpgme_key_unref);
-
- setlocale(LC_ALL, "");
- _session->version = _session->gpgme_check(NULL);
- _session->gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
-
- gpgme_error = _session->gpgme_new(&_session->ctx);
- if (gpgme_error != GPG_ERR_NO_ERROR) {
- dlclose(_session->gpgme);
- free(_session);
- return PEP_INIT_GPGME_INIT_FAILED;
- }
-
- gpgme_error = _session->gpgme_set_protocol(_session->ctx,
- GPGME_PROTOCOL_OpenPGP);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
-
- _session->gpgme_set_armor(_session->ctx, 1);
+ status_result = pgp_init(session);
+ assert(status_result == PEP_STATUS_OK);
+ if (status_result != PEP_STATUS_OK) {
+ free(_session);
+ return status_result;
+ }
assert(LOCAL_DB);
if (LOCAL_DB == NULL) {
- _session->gpgme_release(_session->ctx);
- dlclose(_session->gpgme);
+ pgp_release(session);
free(_session);
return PEP_INIT_CANNOT_OPEN_DB;
}
@@ -442,9 +58,8 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
if (int_result != SQLITE_OK) {
sqlite3_close_v2(_session->db);
- _session->gpgme_release(_session->ctx);
- dlclose(_session->gpgme);
- free(_session);
+ pgp_release(session);
+ free(_session);
return PEP_INIT_CANNOT_OPEN_DB;
}
@@ -453,9 +68,8 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
assert(SYSTEM_DB);
if (SYSTEM_DB == NULL) {
sqlite3_close_v2(_session->db);
- _session->gpgme_release(_session->ctx);
- dlclose(_session->gpgme);
- free(_session);
+ pgp_release(session);
+ free(_session);
return PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
}
@@ -470,9 +84,8 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
if (int_result != SQLITE_OK) {
sqlite3_close_v2(_session->system_db);
sqlite3_close_v2(_session->db);
- _session->gpgme_release(_session->ctx);
- dlclose(_session->gpgme);
- free(_session);
+ pgp_release(session);
+ free(_session);
return PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
}
@@ -634,10 +247,8 @@ DYNAMIC_API void release(PEP_SESSION session)
sqlite3_close_v2(_session->db);
sqlite3_close_v2(_session->system_db);
}
- if (_session->ctx)
- _session->gpgme_release(_session->ctx);
- dlclose(_session->gpgme);
- }
+ pgp_release(session);
+ }
free(_session);
}
@@ -706,471 +317,6 @@ void free_stringlist(stringlist_t *stringlist)
}
}
-DYNAMIC_API PEP_STATUS decrypt_and_verify(
- PEP_SESSION session, const char *ctext, size_t csize,
- char **ptext, size_t *psize, stringlist_t **keylist
- )
-{
- pEpSession *_session = (pEpSession *) session;
-
- PEP_STATUS result;
- gpgme_error_t gpgme_error;
- gpgme_data_t cipher, plain;
- gpgme_data_type_t dt;
-
- stringlist_t *_keylist = NULL;
- int i_key = 0;
-
- assert(_session);
- assert(ctext);
- assert(csize);
- assert(ptext);
- assert(psize);
- assert(keylist);
-
- *ptext = NULL;
- *psize = 0;
- *keylist = NULL;
-
- gpgme_error = _session->gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
- if (gpgme_error != GPG_ERR_NO_ERROR) {
- if (gpgme_error == GPG_ERR_ENOMEM)
- return PEP_OUT_OF_MEMORY;
- else
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_error = _session->gpgme_data_new(&plain);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
- if (gpgme_error != GPG_ERR_NO_ERROR) {
- _session->gpgme_data_release(cipher);
- if (gpgme_error == GPG_ERR_ENOMEM)
- return PEP_OUT_OF_MEMORY;
- else
- return PEP_UNKNOWN_ERROR;
- }
-
- dt = _session->gpgme_data_identify(cipher);
- switch (dt) {
- case GPGME_DATA_TYPE_PGP_SIGNED:
- case GPGME_DATA_TYPE_PGP_OTHER:
- gpgme_error = _session->gpgme_op_decrypt_verify(_session->ctx, cipher,
- plain);
- assert(gpgme_error != GPG_ERR_INV_VALUE);
- assert(gpgme_error != GPG_ERR_NO_DATA);
-
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- {
- gpgme_verify_result_t gpgme_verify_result;
- char *_buffer = NULL;
- size_t reading;
- size_t length = _session->gpgme_data_seek(plain, 0, SEEK_END);
- gpgme_signature_t gpgme_signature;
-
- assert(length != -1);
- _session->gpgme_data_seek(plain, 0, SEEK_SET);
-
- // TODO: make things less memory consuming
- // the following algorithm allocates memory for the complete
- // text
-
- _buffer = malloc(length + 1);
- assert(_buffer);
- if (_buffer == NULL) {
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return PEP_OUT_OF_MEMORY;
- }
-
- reading = _session->gpgme_data_read(plain, _buffer, length);
- assert(length == reading);
-
- gpgme_verify_result =
- _session->gpgme_op_verify_result(_session->ctx);
- assert(gpgme_verify_result);
- gpgme_signature = gpgme_verify_result->signatures;
-
- if (gpgme_signature) {
- stringlist_t *k;
- _keylist = new_stringlist(NULL);
- assert(_keylist);
- if (_keylist == NULL) {
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- free(_buffer);
- return PEP_OUT_OF_MEMORY;
- }
- k = _keylist;
-
- result = PEP_DECRYPTED_AND_VERIFIED;
- do {
- switch (gpgme_signature->status) {
- case GPG_ERR_NO_ERROR:
- k = stringlist_add(k, gpgme_signature->fpr);
- break;
- case GPG_ERR_CERT_REVOKED:
- case GPG_ERR_BAD_SIGNATURE:
- result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
- break;
- case GPG_ERR_SIG_EXPIRED:
- case GPG_ERR_KEY_EXPIRED:
- case GPG_ERR_NO_PUBKEY:
- k = stringlist_add(k, gpgme_signature->fpr);
- if (result == PEP_DECRYPTED_AND_VERIFIED)
- result = PEP_DECRYPTED;
- break;
- case GPG_ERR_GENERAL:
- break;
- default:
- if (result == PEP_DECRYPTED_AND_VERIFIED)
- result = PEP_DECRYPTED;
- break;
- }
- } while ((gpgme_signature = gpgme_signature->next));
- } else {
- result = PEP_DECRYPTED;
- }
-
- if (result == PEP_DECRYPTED_AND_VERIFIED
- || result == PEP_DECRYPTED) {
- *ptext = _buffer;
- *psize = reading;
- (*ptext)[*psize] = 0; // safeguard for naive users
- *keylist = _keylist;
- }
- else {
- free_stringlist(_keylist);
- free(_buffer);
- }
- break;
- }
- case GPG_ERR_DECRYPT_FAILED:
- result = PEP_DECRYPT_WRONG_FORMAT;
- break;
- case GPG_ERR_BAD_PASSPHRASE:
- NOT_IMPLEMENTED;
- default:
- {
- gpgme_decrypt_result_t gpgme_decrypt_result = _session->gpgme_op_decrypt_result(_session->ctx);
- result = PEP_DECRYPT_NO_KEY;
-
- if (gpgme_decrypt_result != NULL) {
- if (gpgme_decrypt_result->unsupported_algorithm)
- *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
- else
- *keylist = new_stringlist("");
- assert(*keylist);
- if (*keylist == NULL) {
- result = PEP_OUT_OF_MEMORY;
- break;
- }
- stringlist_t *_keylist = *keylist;
- for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
- _keylist = stringlist_add(_keylist, r->keyid);
- assert(_keylist);
- if (_keylist == NULL) {
- free_stringlist(*keylist);
- *keylist = NULL;
- result = PEP_OUT_OF_MEMORY;
- break;
- }
- }
- if (result == PEP_OUT_OF_MEMORY)
- break;
- }
- }
- }
- break;
-
- default:
- result = PEP_DECRYPT_WRONG_FORMAT;
- }
-
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return result;
-}
-
-DYNAMIC_API PEP_STATUS verify_text(
- PEP_SESSION session, const char *text, size_t size,
- const char *signature, size_t sig_size, stringlist_t **keylist
- )
-{
- pEpSession *_session = (pEpSession *) session;
-
- PEP_STATUS result;
- gpgme_error_t gpgme_error;
- gpgme_data_t d_text, d_sig;
- stringlist_t *_keylist;
-
- assert(session);
- assert(text);
- assert(size);
- assert(signature);
- assert(sig_size);
- assert(keylist);
-
- *keylist = NULL;
-
- gpgme_error = _session->gpgme_data_new_from_mem(&d_text, text, size, 0);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
- if (gpgme_error != GPG_ERR_NO_ERROR) {
- if (gpgme_error == GPG_ERR_ENOMEM)
- return PEP_OUT_OF_MEMORY;
- else
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_error = _session->gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
- if (gpgme_error != GPG_ERR_NO_ERROR) {
- _session->gpgme_data_release(d_text);
- if (gpgme_error == GPG_ERR_ENOMEM)
- return PEP_OUT_OF_MEMORY;
- else
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_error = _session->gpgme_op_verify(_session->ctx, d_sig, d_text, NULL);
- assert(gpgme_error != GPG_ERR_INV_VALUE);
-
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- {
- gpgme_verify_result_t gpgme_verify_result;
- gpgme_signature_t gpgme_signature;
-
- gpgme_verify_result =
- _session->gpgme_op_verify_result(_session->ctx);
- assert(gpgme_verify_result);
- gpgme_signature = gpgme_verify_result->signatures;
-
- if (gpgme_signature) {
- stringlist_t *k;
- _keylist = new_stringlist(NULL);
- assert(_keylist);
- if (_keylist == NULL) {
- _session->gpgme_data_release(d_text);
- _session->gpgme_data_release(d_sig);
- return PEP_OUT_OF_MEMORY;
- }
- k = _keylist;
-
- result = PEP_VERIFIED;
- do {
- k = stringlist_add(k, gpgme_signature->fpr);
- if (k == NULL) {
- free_stringlist(_keylist);
- _session->gpgme_data_release(d_text);
- _session->gpgme_data_release(d_sig);
- return PEP_OUT_OF_MEMORY;
- }
- if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
- if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
- || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
- if (result == PEP_VERIFIED
- || result == PEP_VERIFIED_AND_TRUSTED)
- result = PEP_UNENCRYPTED;
- }
- else {
- result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
- break;
- }
- }
- else {
- if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
- if (result == PEP_VERIFIED)
- result = PEP_VERIFIED_AND_TRUSTED;
- }
- if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
- // good
- }
- else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
- result = PEP_VERIFY_NO_KEY;
- }
- else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
- if (result == PEP_VERIFIED
- || result == PEP_VERIFIED_AND_TRUSTED)
- result = PEP_UNENCRYPTED;
- }
- else {
- // do nothing
- }
- }
- } while ((gpgme_signature = gpgme_signature->next));
- *keylist = _keylist;
- } else {
- result = PEP_UNENCRYPTED;
- }
- break;
- }
- break;
- case GPG_ERR_NO_DATA:
- result = PEP_DECRYPT_WRONG_FORMAT;
- break;
- case GPG_ERR_INV_VALUE:
- default:
- result = PEP_UNKNOWN_ERROR;
- break;
- }
-
- _session->gpgme_data_release(d_text);
- _session->gpgme_data_release(d_sig);
-
- return result;
-}
-
-DYNAMIC_API PEP_STATUS encrypt_and_sign(
- PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
- size_t psize, char **ctext, size_t *csize
- )
-{
- pEpSession *_session = (pEpSession *) session;
-
- PEP_STATUS result;
- gpgme_error_t gpgme_error;
- gpgme_data_t plain, cipher;
- gpgme_key_t *rcpt;
- gpgme_encrypt_flags_t flags;
- const stringlist_t *_keylist;
- int i, j;
-
- assert(_session);
- assert(keylist);
- assert(ptext);
- assert(psize);
- assert(ctext);
- assert(csize);
-
- *ctext = NULL;
- *csize = 0;
-
- gpgme_error = _session->gpgme_data_new_from_mem(&plain, ptext, psize, 0);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
- if (gpgme_error != GPG_ERR_NO_ERROR) {
- if (gpgme_error == GPG_ERR_ENOMEM)
- return PEP_OUT_OF_MEMORY;
- else
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_error = _session->gpgme_data_new(&cipher);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
- if (gpgme_error != GPG_ERR_NO_ERROR) {
- _session->gpgme_data_release(plain);
- if (gpgme_error == GPG_ERR_ENOMEM)
- return PEP_OUT_OF_MEMORY;
- else
- return PEP_UNKNOWN_ERROR;
- }
-
- rcpt = (gpgme_key_t *) calloc(stringlist_length(keylist) + 1,
- sizeof(gpgme_key_t));
- assert(rcpt);
- if (rcpt == NULL) {
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return PEP_OUT_OF_MEMORY;
- }
-
- _session->gpgme_signers_clear(_session->ctx);
-
- for (_keylist=keylist, i=0; _keylist!=NULL; _keylist=_keylist->next, i++) {
- assert(_keylist->value);
- gpgme_error = _session->gpgme_get_key(_session->ctx, _keylist->value,
- &rcpt[i], 0);
- assert(gpgme_error != GPG_ERR_ENOMEM);
-
- switch (gpgme_error) {
- case GPG_ERR_ENOMEM:
- for (j=0; jgpgme_key_unref(rcpt[j]);
- free(rcpt);
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return PEP_OUT_OF_MEMORY;
- case GPG_ERR_NO_ERROR:
- if (i == 0) {
- gpgme_error_t _gpgme_error = _session->gpgme_signers_add(_session->ctx, rcpt[0]);
- assert(_gpgme_error == GPG_ERR_NO_ERROR);
- }
- break;
- case GPG_ERR_EOF:
- for (j=0; jgpgme_key_unref(rcpt[j]);
- free(rcpt);
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return PEP_KEY_NOT_FOUND;
- case GPG_ERR_AMBIGUOUS_NAME:
- for (j=0; jgpgme_key_unref(rcpt[j]);
- free(rcpt);
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return PEP_KEY_HAS_AMBIG_NAME;
- default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
- // FPR is not a fingerprint or key ID
- for (j=0; jgpgme_key_unref(rcpt[j]);
- free(rcpt);
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return PEP_GET_KEY_FAILED;
- }
- }
-
- // TODO: remove that and replace with proper key management
- flags = GPGME_ENCRYPT_ALWAYS_TRUST;
-
- gpgme_error = _session->gpgme_op_encrypt_sign(_session->ctx, rcpt, flags,
- plain, cipher);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- {
- char *_buffer = NULL;
- size_t reading;
- size_t length = _session->gpgme_data_seek(cipher, 0, SEEK_END);
- assert(length != -1);
- _session->gpgme_data_seek(cipher, 0, SEEK_SET);
-
- // TODO: make things less memory consuming
- // the following algorithm allocates a buffer for the complete text
-
- _buffer = (char *) malloc(length + 1);
- assert(_buffer);
- if (_buffer == NULL) {
- for (j=0; jgpgme_key_unref(rcpt[j]);
- free(rcpt);
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return PEP_OUT_OF_MEMORY;
- }
-
- reading = _session->gpgme_data_read(cipher, _buffer, length);
- assert(length == reading);
-
- *ctext = _buffer;
- *csize = reading;
- (*ctext)[*csize] = 0; // safeguard for naive users
- result = PEP_STATUS_OK;
- break;
- }
- default:
- result = PEP_UNKNOWN_ERROR;
- }
-
- for (j=0; jgpgme_key_unref(rcpt[j]);
- free(rcpt);
- _session->gpgme_data_release(plain);
- _session->gpgme_data_release(cipher);
- return result;
-}
-
DYNAMIC_API PEP_STATUS log_event(
PEP_SESSION session, const char *title, const char *entity,
const char *description, const char *comment
@@ -1526,402 +672,6 @@ DYNAMIC_API PEP_STATUS set_identity(
return PEP_COMMIT_FAILED;
}
-DYNAMIC_API PEP_STATUS generate_keypair(
- PEP_SESSION session, pEp_identity *identity
- )
-{
- pEpSession *_session = (pEpSession *) session;
- gpgme_error_t gpgme_error;
- char *parms;
- const char *template =
- "\n"
- "Key-Type: RSA\n"
- "Key-Length: 4096\n"
- "Name-Real: %s\n"
- "Name-Email: %s\n"
- /* "Passphrase: %s\n" */
- "Expire-Date: 1y\n"
- "\n";
- int result;
- gpgme_genkey_result_t gpgme_genkey_result;
-
- assert(session);
- assert(identity);
- assert(identity->address);
- assert(identity->fpr == NULL);
- assert(identity->username);
-
- parms = calloc(1, PARMS_MAX);
- assert(parms);
- if (parms == NULL)
- return PEP_OUT_OF_MEMORY;
-
- result = snprintf(parms, PARMS_MAX, template, identity->username,
- identity->address); // , _session->passphrase);
- assert(result < PARMS_MAX);
- if (result >= PARMS_MAX) {
- free(parms);
- return PEP_BUFFER_TOO_SMALL;
- }
-
- gpgme_error = _session->gpgme_op_genkey(_session->ctx, parms, NULL, NULL);
- free(parms);
-
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_INV_VALUE:
- return PEP_ILLEGAL_VALUE;
- case GPG_ERR_GENERAL:
- return PEP_CANNOT_CREATE_KEY;
- default:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_genkey_result = _session->gpgme_op_genkey_result(_session->ctx);
- assert(gpgme_genkey_result);
- assert(gpgme_genkey_result->fpr);
-
- identity->fpr = strdup(gpgme_genkey_result->fpr);
-
- return PEP_STATUS_OK;
-}
-
-PEP_STATUS delete_keypair(PEP_SESSION session, const char *fpr)
-{
- pEpSession *_session = (pEpSession *) session;
- gpgme_error_t gpgme_error;
- gpgme_key_t key;
-
- assert(session);
- assert(fpr);
-
- gpgme_error = _session->gpgme_get_key(_session->ctx, fpr, &key, 0);
- assert(gpgme_error != GPG_ERR_ENOMEM);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_EOF:
- return PEP_KEY_NOT_FOUND;
- case GPG_ERR_INV_VALUE:
- return PEP_ILLEGAL_VALUE;
- case GPG_ERR_AMBIGUOUS_NAME:
- return PEP_KEY_HAS_AMBIG_NAME;
- case GPG_ERR_ENOMEM:
- return PEP_OUT_OF_MEMORY;
- default:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_error = _session->gpgme_op_delete(_session->ctx, key, 1);
- _session->gpgme_key_unref(key);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_INV_VALUE:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- case GPG_ERR_NO_PUBKEY:
- assert(0);
- return PEP_KEY_NOT_FOUND;
- case GPG_ERR_AMBIGUOUS_NAME:
- assert(0);
- return PEP_KEY_HAS_AMBIG_NAME;
- default:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- }
-
- return PEP_STATUS_OK;
-}
-
-PEP_STATUS import_key(PEP_SESSION session, const char *key_data, size_t size)
-{
- pEpSession *_session = (pEpSession *) session;
- gpgme_error_t gpgme_error;
- gpgme_data_t dh;
-
- assert(session);
- assert(key_data);
-
- gpgme_error = _session->gpgme_data_new_from_mem(&dh, key_data, size, 0);
- assert(gpgme_error != GPG_ERR_ENOMEM);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_ENOMEM:
- return PEP_OUT_OF_MEMORY;
- case GPG_ERR_INV_VALUE:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- default:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_error = _session->gpgme_op_import(_session->ctx, dh);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_INV_VALUE:
- assert(0);
- _session->gpgme_data_release(dh);
- return PEP_UNKNOWN_ERROR;
- case GPG_ERR_NO_DATA:
- _session->gpgme_data_release(dh);
- return PEP_ILLEGAL_VALUE;
- default:
- assert(0);
- _session->gpgme_data_release(dh);
- return PEP_UNKNOWN_ERROR;
- }
-
- _session->gpgme_data_release(dh);
- return PEP_STATUS_OK;
-}
-
-PEP_STATUS export_key(
- PEP_SESSION session, const char *fpr, char **key_data, size_t *size
- )
-{
- pEpSession *_session = (pEpSession *) session;
- gpgme_error_t gpgme_error;
- gpgme_data_t dh;
- size_t _size;
- char *buffer;
- int reading;
-
- assert(session);
- assert(fpr);
- assert(key_data);
- assert(size);
-
- gpgme_error = _session->gpgme_data_new(&dh);
- assert(gpgme_error != GPG_ERR_ENOMEM);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_ENOMEM:
- return PEP_OUT_OF_MEMORY;
- case GPG_ERR_INV_VALUE:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- default:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- }
-
- gpgme_error = _session->gpgme_op_export(_session->ctx, fpr,
- GPGME_EXPORT_MODE_MINIMAL, dh);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_EOF:
- _session->gpgme_data_release(dh);
- return PEP_KEY_NOT_FOUND;
- case GPG_ERR_INV_VALUE:
- assert(0);
- _session->gpgme_data_release(dh);
- return PEP_UNKNOWN_ERROR;
- default:
- assert(0);
- _session->gpgme_data_release(dh);
- return PEP_UNKNOWN_ERROR;
- };
-
- _size = _session->gpgme_data_seek(dh, 0, SEEK_END);
- assert(_size != -1);
- _session->gpgme_data_seek(dh, 0, SEEK_SET);
-
- buffer = malloc(_size + 1);
- assert(buffer);
- if (buffer == NULL) {
- _session->gpgme_data_release(dh);
- return PEP_OUT_OF_MEMORY;
- }
-
- reading = _session->gpgme_data_read(dh, buffer, _size);
- assert(_size == reading);
-
- // safeguard for the naive user
- buffer[_size] = 0;
-
- *key_data = buffer;
- *size = _size;
-
- _session->gpgme_data_release(dh);
- return PEP_STATUS_OK;
-}
-
-static void _switch_mode(pEpSession *_session, gpgme_keylist_mode_t remove_mode,
- gpgme_keylist_mode_t add_mode)
-{
- gpgme_error_t gpgme_error;
- gpgme_keylist_mode_t mode;
-
- mode = _session->gpgme_get_keylist_mode(_session->ctx);
-
- mode &= ~remove_mode;
- mode |= add_mode;
-
- gpgme_error = _session->gpgme_set_keylist_mode(_session->ctx, mode);
- assert(gpgme_error == GPG_ERR_NO_ERROR);
-}
-
-PEP_STATUS recv_key(PEP_SESSION session, const char *pattern)
-{
- pEpSession *_session = (pEpSession *) session;
- gpgme_error_t gpgme_error;
- gpgme_key_t key;
-
- assert(session);
- assert(pattern);
-
- _switch_mode(_session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
-
- gpgme_error = _session->gpgme_op_keylist_start(_session->ctx, pattern, 0);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_INV_VALUE:
- assert(0);
- _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
- GPGME_KEYLIST_MODE_LOCAL);
- return PEP_UNKNOWN_ERROR;
- default:
- _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
- GPGME_KEYLIST_MODE_LOCAL);
- return PEP_GET_KEY_FAILED;
- };
-
- do {
- gpgme_error = _session->gpgme_op_keylist_next(_session->ctx, &key);
- assert(gpgme_error != GPG_ERR_INV_VALUE);
- switch (gpgme_error) {
- case GPG_ERR_EOF:
- break;
- case GPG_ERR_NO_ERROR:
- {
- gpgme_error_t gpgme_error;
- gpgme_key_t keys[2];
-
- keys[0] = key;
- keys[1] = NULL;
-
- gpgme_error = _session->gpgme_op_import_keys(_session->ctx, keys);
- _session->gpgme_key_unref(key);
- assert(gpgme_error != GPG_ERR_INV_VALUE);
- assert(gpgme_error != GPG_ERR_CONFLICT);
- }
- break;
- case GPG_ERR_ENOMEM:
- _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
- GPGME_KEYLIST_MODE_LOCAL);
- _session->gpgme_op_keylist_end(_session->ctx);
- return PEP_OUT_OF_MEMORY;
- default:
- // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
- // reading first key
-#ifndef NDEBUG
- fprintf(stderr, "warning: unknown result 0x%x of"
- " gpgme_op_keylist_next()\n", gpgme_error);
-#endif
- gpgme_error = GPG_ERR_EOF;
- break;
- };
- } while (gpgme_error != GPG_ERR_EOF);
-
- _session->gpgme_op_keylist_end(_session->ctx);
- _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
- GPGME_KEYLIST_MODE_LOCAL);
- return PEP_STATUS_OK;
-}
-
-DYNAMIC_API PEP_STATUS find_keys(
- PEP_SESSION session, const char *pattern, stringlist_t **keylist
- )
-{
- pEpSession *_session = (pEpSession *) session;
- gpgme_error_t gpgme_error;
- gpgme_key_t key;
- stringlist_t *_keylist;
- char *fpr;
-
- assert(session);
- assert(pattern);
- assert(keylist);
-
- *keylist = NULL;
-
- gpgme_error = _session->gpgme_op_keylist_start(_session->ctx, pattern, 0);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_INV_VALUE:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- default:
- return PEP_GET_KEY_FAILED;
- };
-
- _keylist = new_stringlist(NULL);
- stringlist_t *_k = _keylist;
-
- do {
- gpgme_error = _session->gpgme_op_keylist_next(_session->ctx, &key);
- assert(gpgme_error != GPG_ERR_INV_VALUE);
- switch (gpgme_error) {
- case GPG_ERR_EOF:
- break;
- case GPG_ERR_NO_ERROR:
- assert(key);
- assert(key->subkeys);
- fpr = key->subkeys->fpr;
- assert(fpr);
- _k = stringlist_add(_k, fpr);
- assert(_k);
- if (_k != NULL)
- break;
- case GPG_ERR_ENOMEM:
- free_stringlist(_keylist);
- _session->gpgme_op_keylist_end(_session->ctx);
- return PEP_OUT_OF_MEMORY;
- default:
- // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
- // reading first key
-#ifndef NDEBUG
- fprintf(stderr, "warning: unknown result 0x%x of"
- " gpgme_op_keylist_next()\n", gpgme_error);
-#endif
- gpgme_error = GPG_ERR_EOF;
- break;
- };
- } while (gpgme_error != GPG_ERR_EOF);
-
- _session->gpgme_op_keylist_end(_session->ctx);
- *keylist = _keylist;
- return PEP_STATUS_OK;
-}
-
-PEP_STATUS send_key(PEP_SESSION session, const char *pattern)
-{
- pEpSession *_session = (pEpSession *) session;
- gpgme_error_t gpgme_error;
-
- assert(session);
- assert(pattern);
-
- gpgme_error = _session->gpgme_op_export(_session->ctx, pattern,
- GPGME_EXPORT_MODE_EXTERN, NULL);
- assert(gpgme_error != GPG_ERR_INV_VALUE);
- if (gpgme_error == GPG_ERR_NO_ERROR)
- return PEP_STATUS_OK;
- else
- return PEP_CANNOT_SEND_KEY;
-}
-
void pEp_free(void *p)
{
free(p);
@@ -1971,105 +721,76 @@ DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
return status;
}
-DYNAMIC_API PEP_STATUS get_key_rating(
- PEP_SESSION session,
- const char *fpr,
- PEP_comm_type *comm_type
+DYNAMIC_API PEP_STATUS decrypt_and_verify(
+ PEP_SESSION session, const char *ctext, size_t csize,
+ char **ptext, size_t *psize, stringlist_t **keylist
)
{
- pEpSession *_session = (pEpSession *) session;
- PEP_STATUS status = PEP_STATUS_OK;
- gpgme_error_t gpgme_error;
- gpgme_key_t key;
+ return pgp_decrypt_and_verify(session, ctext, csize, ptext, psize, keylist);
+}
- assert(session);
- assert(fpr);
- assert(comm_type);
-
- *comm_type = PEP_ct_unknown;
-
- gpgme_error = _session->gpgme_op_keylist_start(_session->ctx, fpr, 0);
- switch (gpgme_error) {
- case GPG_ERR_NO_ERROR:
- break;
- case GPG_ERR_INV_VALUE:
- assert(0);
- return PEP_UNKNOWN_ERROR;
- default:
- return PEP_GET_KEY_FAILED;
- };
+DYNAMIC_API PEP_STATUS encrypt_and_sign(
+ PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
+ size_t psize, char **ctext, size_t *csize
+ )
+{
+ return pgp_encrypt_and_sign(session, keylist, ptext, psize, ctext, csize);
+}
- gpgme_error = _session->gpgme_op_keylist_next(_session->ctx, &key);
- assert(gpgme_error != GPG_ERR_INV_VALUE);
+DYNAMIC_API PEP_STATUS verify_text(
+ PEP_SESSION session, const char *text, size_t size,
+ const char *signature, size_t sig_size, stringlist_t **keylist
+ )
+{
+ return pgp_verify_text(session, text, size, signature, sig_size, keylist);
+}
- if (key == NULL) {
- _session->gpgme_op_keylist_end(_session->ctx);
- return PEP_KEY_NOT_FOUND;
- }
+DYNAMIC_API PEP_STATUS delete_keypair(PEP_SESSION session, const char *fpr)
+{
+ return pgp_delete_keypair(session, fpr);
+}
- switch (key->protocol) {
- case GPGME_PROTOCOL_OpenPGP:
- case GPGME_PROTOCOL_DEFAULT:
- *comm_type = PEP_ct_OpenPGP_unconfirmed;
- break;
- case GPGME_PROTOCOL_CMS:
- *comm_type = PEP_ct_CMS_unconfirmed;
- break;
- default:
- *comm_type = PEP_ct_unknown;
- _session->gpgme_op_keylist_end(_session->ctx);
- return PEP_STATUS_OK;
- }
+DYNAMIC_API PEP_STATUS export_key(
+ PEP_SESSION session, const char *fpr, char **key_data, size_t *size
+ )
+{
+ return pgp_export_key(session, fpr, key_data, size);
+}
- switch (gpgme_error) {
- case GPG_ERR_EOF:
- break;
- case GPG_ERR_NO_ERROR:
- assert(key);
- assert(key->subkeys);
- for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
- if (sk->length < 1024)
- *comm_type = PEP_ct_key_too_short;
- else if (
- (
- (sk->pubkey_algo == GPGME_PK_RSA)
- || (sk->pubkey_algo == GPGME_PK_RSA_E)
- || (sk->pubkey_algo == GPGME_PK_RSA_S)
- )
- && sk->length == 1024
- )
- *comm_type = PEP_ct_OpenPGP_1024_RSA_unconfirmed;
-
- if (sk->invalid) {
- *comm_type = PEP_ct_key_b0rken;
- break;
- }
- if (sk->expired) {
- *comm_type = PEP_ct_key_expired;
- break;
- }
- if (sk->revoked) {
- *comm_type = PEP_ct_key_revoked;
- break;
- }
- }
- break;
- case GPG_ERR_ENOMEM:
- _session->gpgme_op_keylist_end(_session->ctx);
- *comm_type = PEP_ct_unknown;
- return PEP_OUT_OF_MEMORY;
- default:
- // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
- // reading first key
-#ifndef NDEBUG
- fprintf(stderr, "warning: unknown result 0x%x of"
- " gpgme_op_keylist_next()\n", gpgme_error);
-#endif
- gpgme_error = GPG_ERR_EOF;
- break;
- };
+DYNAMIC_API PEP_STATUS find_keys(
+ PEP_SESSION session, const char *pattern, stringlist_t **keylist
+ )
+{
+ return pgp_find_keys(session, pattern, keylist);
+}
+
+DYNAMIC_API PEP_STATUS generate_keypair(
+ PEP_SESSION session, pEp_identity *identity
+ )
+{
+ return pgp_generate_keypair(session, identity);
+}
+
+DYNAMIC_API PEP_STATUS get_key_rating(
+ PEP_SESSION session,
+ const char *fpr,
+ PEP_comm_type *comm_type
+ )
+{
+ return pgp_get_key_rating(session, fpr, comm_type);
+}
- _session->gpgme_op_keylist_end(_session->ctx);
+DYNAMIC_API PEP_STATUS import_key(PEP_SESSION session, const char *key_data, size_t size)
+{
+ return pgp_import_key(session, key_data, size);
+}
- return status;
+DYNAMIC_API PEP_STATUS recv_key(PEP_SESSION session, const char *pattern)
+{
+ return pgp_recv_key(session, pattern);
+}
+
+DYNAMIC_API PEP_STATUS send_key(PEP_SESSION session, const char *pattern)
+{
+ return pgp_send_key(session, pattern);
}
diff --git a/src/pEp_internal.h b/src/pEp_internal.h
new file mode 100644
index 00000000..9f4a1a9a
--- /dev/null
+++ b/src/pEp_internal.h
@@ -0,0 +1,80 @@
+#define PEP_ENGINE_VERSION "0.5.0"
+
+// this is 20 safewords with 79 chars max
+#define MAX_SAFEWORDS_SPACE (20 * 80)
+
+// XML parameters string
+#define PARMS_MAX 32768
+
+// maximum busy wait time in ms
+#define BUSY_WAIT_TIME 5000
+
+// maximum line length for reading gpg.conf
+#define MAX_LINELENGTH 1024
+
+// default keyserver
+#define DEFAULT_KEYSERVER "hkp://keys.gnupg.net"
+
+#ifdef WIN32
+#include "platform_windows.h"
+#define LOCAL_DB windoze_local_db()
+#define SYSTEM_DB windoze_system_db()
+#define LIBGPGME "libgpgme-11.dll"
+#else // UNIX
+#define _POSIX_C_SOURCE 200809L
+#include
+#include "platform_unix.h"
+#define LOCAL_DB unix_local_db()
+#ifndef SYSTEM_DB
+#define SYSTEM_DB "/usr/share/pEp/system.db"
+#endif
+#ifndef LIBGPGME
+#define LIBGPGME "libgpgme-pthread.so"
+#endif
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#ifndef NDEBUG
+#include
+#endif
+
+#ifndef NO_GPG
+#include
+#endif
+
+#include "sqlite3.h"
+
+#define _EXPORT_PEP_ENGINE_DLL
+#include "pEpEngine.h"
+#ifndef NO_GPG
+#include "pgp_gpg_internal.h"
+#endif
+
+#define NOT_IMPLEMENTED assert(0)
+
+typedef struct {
+ const char *version;
+
+#ifndef NO_GPG
+ void *gpgme;
+ struct gpg_s gpg;
+ gpgme_ctx_t ctx;
+#endif
+
+ sqlite3 *db;
+ sqlite3 *system_db;
+
+ sqlite3_stmt *log;
+ sqlite3_stmt *safeword;
+ sqlite3_stmt *get_identity;
+ sqlite3_stmt *set_person;
+ sqlite3_stmt *set_pgp_keypair;
+ sqlite3_stmt *set_identity;
+ sqlite3_stmt *set_trust;
+ sqlite3_stmt *get_trust;
+} pEpSession;
diff --git a/src/pgp_gpg.c b/src/pgp_gpg.c
new file mode 100644
index 00000000..7635be68
--- /dev/null
+++ b/src/pgp_gpg.c
@@ -0,0 +1,1202 @@
+#include "pgp_gpg.h"
+#include "pEp_internal.h"
+
+static bool ensure_keyserver()
+{
+ static char buf[MAX_LINELENGTH];
+ int n;
+ FILE *f = fopen(gpg_conf(), "r");
+
+ if (f != NULL) {
+ while (!feof(f)) {
+ char * s = fgets(buf, MAX_LINELENGTH, f);
+ if (s && !feof(f)) {
+ char * t = strtok(s, " ");
+ if (t && strcmp(t, "keyserver") == 0) {
+ fclose(f);
+ return true;
+ }
+ }
+ }
+ f = freopen(gpg_conf(), "a", f);
+ }
+ else {
+ f = fopen(gpg_conf(), "w");
+ }
+
+ assert(f);
+ if (f == NULL)
+ return false;
+
+ n = fprintf(f, "keyserver %s\n", DEFAULT_KEYSERVER);
+ assert(n >= 0);
+ fclose(f);
+
+ return true;
+}
+
+PEP_STATUS pgp_init(PEP_SESSION session)
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+ bool bResult = ensure_keyserver();
+ assert(bResult);
+
+ _session->gpgme = dlopen(LIBGPGME, RTLD_LAZY);
+ if (_session->gpgme == NULL) {
+ free(_session);
+ return PEP_INIT_CANNOT_LOAD_GPGME;
+ }
+
+ memset(&(_session->gpg), 0, sizeof(struct gpg_s));
+
+ _session->gpg.gpgme_set_locale
+ = (gpgme_set_locale_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_set_locale");
+ assert(_session->gpg.gpgme_set_locale);
+
+ _session->gpg.gpgme_check
+ = (gpgme_check_version_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_check_version");
+ assert(_session->gpg.gpgme_check);
+
+ _session->gpg.gpgme_new
+ = (gpgme_new_t) (intptr_t) dlsym(_session->gpgme, "gpgme_new");
+ assert(_session->gpg.gpgme_new);
+
+ _session->gpg.gpgme_release
+ = (gpgme_release_t) (intptr_t) dlsym(_session->gpgme, "gpgme_release");
+ assert(_session->gpg.gpgme_release);
+
+ _session->gpg.gpgme_set_protocol
+ = (gpgme_set_protocol_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_set_protocol");
+ assert(_session->gpg.gpgme_set_protocol);
+
+ _session->gpg.gpgme_set_armor
+ = (gpgme_set_armor_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_set_armor");
+ assert(_session->gpg.gpgme_set_armor);
+
+ _session->gpg.gpgme_data_new
+ = (gpgme_data_new_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_data_new");
+ assert(_session->gpg.gpgme_data_new);
+
+ _session->gpg.gpgme_data_new_from_mem
+ = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_data_new_from_mem");
+ assert(_session->gpg.gpgme_data_new_from_mem);
+
+ _session->gpg.gpgme_data_release
+ = (gpgme_data_release_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_data_release");
+ assert(_session->gpg.gpgme_data_release);
+
+ _session->gpg.gpgme_data_identify
+ = (gpgme_data_identify_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_data_identify");
+ assert(_session->gpg.gpgme_data_identify);
+ _session->gpg.gpgme_data_seek
+ = (gpgme_data_seek_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_data_seek");
+ assert(_session->gpg.gpgme_data_seek);
+
+ _session->gpg.gpgme_data_read
+ = (gpgme_data_read_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_data_read");
+ assert(_session->gpg.gpgme_data_read);
+
+ _session->gpg.gpgme_op_decrypt
+ = (gpgme_op_decrypt_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_decrypt");
+ assert(_session->gpg.gpgme_op_decrypt);
+
+ _session->gpg.gpgme_op_verify
+ = (gpgme_op_verify_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_verify");
+ assert(_session->gpg.gpgme_op_verify);
+
+ _session->gpg.gpgme_op_decrypt_verify
+ = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_decrypt_verify");
+ assert(_session->gpg.gpgme_op_decrypt_verify);
+
+ _session->gpg.gpgme_op_decrypt_result
+ = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_decrypt_result");
+ assert(_session->gpg.gpgme_op_decrypt_result);
+
+ _session->gpg.gpgme_op_encrypt_sign
+ = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_encrypt_sign");
+ assert(_session->gpg.gpgme_op_encrypt_sign);
+
+ _session->gpg.gpgme_op_verify_result
+ = (gpgme_op_verify_result_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_verify_result");
+ assert(_session->gpg.gpgme_op_verify_result);
+
+ _session->gpg.gpgme_signers_clear
+ = (gpgme_signers_clear_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_signers_clear");
+ assert(_session->gpg.gpgme_signers_clear);
+
+ _session->gpg.gpgme_signers_add
+ = (gpgme_signers_add_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_signers_add");
+ assert(_session->gpg.gpgme_signers_add);
+ _session->gpg.gpgme_get_key
+ = (gpgme_get_key_t) (intptr_t) dlsym(_session->gpgme, "gpgme_get_key");
+ assert(_session->gpg.gpgme_get_key);
+
+ _session->gpg.gpgme_op_genkey
+ = (gpgme_op_genkey_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_genkey");
+ assert(_session->gpg.gpgme_op_genkey);
+
+ _session->gpg.gpgme_op_genkey_result
+ = (gpgme_op_genkey_result_t) (intptr_t) dlsym(_session->gpgme,
+ "gpgme_op_genkey_result");
+ assert(_session->gpg.gpgme_op_genkey_result);
+
+ _session->gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_op_delete");
+ assert(_session->gpg.gpgme_op_delete);
+
+ _session->gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_op_import");
+ assert(_session->gpg.gpgme_op_import);
+
+ _session->gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_op_export");
+ assert(_session->gpg.gpgme_op_export);
+
+ _session->gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_set_keylist_mode");
+ assert(_session->gpg.gpgme_set_keylist_mode);
+
+ _session->gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_get_keylist_mode");
+ assert(_session->gpg.gpgme_get_keylist_mode);
+
+ _session->gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_op_keylist_start");
+ assert(_session->gpg.gpgme_op_keylist_start);
+
+ _session->gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_op_keylist_next");
+ assert(_session->gpg.gpgme_op_keylist_next);
+
+ _session->gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_op_keylist_end");
+ assert(_session->gpg.gpgme_op_keylist_end);
+
+ _session->gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_op_import_keys");
+ assert(_session->gpg.gpgme_op_import_keys);
+
+ _session->gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_key_ref");
+ assert(_session->gpg.gpgme_key_ref);
+
+ _session->gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
+ dlsym(_session->gpgme, "gpgme_key_unref");
+ assert(_session->gpg.gpgme_key_unref);
+
+ setlocale(LC_ALL, "");
+ _session->version = _session->gpg.gpgme_check(NULL);
+ _session->gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
+
+ gpgme_error = _session->gpg.gpgme_new(&_session->ctx);
+ if (gpgme_error != GPG_ERR_NO_ERROR) {
+ dlclose(_session->gpgme);
+ free(_session);
+ return PEP_INIT_GPGME_INIT_FAILED;
+ }
+
+ gpgme_error = _session->gpg.gpgme_set_protocol(_session->ctx,
+ GPGME_PROTOCOL_OpenPGP);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+
+ _session->gpg.gpgme_set_armor(_session->ctx, 1);
+
+ return PEP_STATUS_OK;
+}
+
+void pgp_release(PEP_SESSION session)
+{
+ pEpSession *_session = (pEpSession *) session;
+ if (_session->ctx)
+ _session->gpg.gpgme_release(_session->ctx);
+ _session->ctx = NULL;
+ memset(&(_session->gpg), 0, sizeof(struct gpg_s));
+ dlclose(_session->gpgme);
+}
+
+PEP_STATUS pgp_decrypt_and_verify(
+ PEP_SESSION session, const char *ctext, size_t csize,
+ char **ptext, size_t *psize, stringlist_t **keylist
+ )
+{
+ pEpSession *_session = (pEpSession *) session;
+
+ PEP_STATUS result;
+ gpgme_error_t gpgme_error;
+ gpgme_data_t cipher, plain;
+ gpgme_data_type_t dt;
+
+ stringlist_t *_keylist = NULL;
+ int i_key = 0;
+
+ assert(_session);
+ assert(ctext);
+ assert(csize);
+ assert(ptext);
+ assert(psize);
+ assert(keylist);
+
+ *ptext = NULL;
+ *psize = 0;
+ *keylist = NULL;
+
+ gpgme_error = _session->gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+ if (gpgme_error != GPG_ERR_NO_ERROR) {
+ if (gpgme_error == GPG_ERR_ENOMEM)
+ return PEP_OUT_OF_MEMORY;
+ else
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_error = _session->gpg.gpgme_data_new(&plain);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+ if (gpgme_error != GPG_ERR_NO_ERROR) {
+ _session->gpg.gpgme_data_release(cipher);
+ if (gpgme_error == GPG_ERR_ENOMEM)
+ return PEP_OUT_OF_MEMORY;
+ else
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ dt = _session->gpg.gpgme_data_identify(cipher);
+ switch (dt) {
+ case GPGME_DATA_TYPE_PGP_SIGNED:
+ case GPGME_DATA_TYPE_PGP_OTHER:
+ gpgme_error = _session->gpg.gpgme_op_decrypt_verify(_session->ctx, cipher,
+ plain);
+ assert(gpgme_error != GPG_ERR_INV_VALUE);
+ assert(gpgme_error != GPG_ERR_NO_DATA);
+
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ {
+ gpgme_verify_result_t gpgme_verify_result;
+ char *_buffer = NULL;
+ size_t reading;
+ size_t length = _session->gpg.gpgme_data_seek(plain, 0, SEEK_END);
+ gpgme_signature_t gpgme_signature;
+
+ assert(length != -1);
+ _session->gpg.gpgme_data_seek(plain, 0, SEEK_SET);
+
+ // TODO: make things less memory consuming
+ // the following algorithm allocates memory for the complete
+ // text
+
+ _buffer = malloc(length + 1);
+ assert(_buffer);
+ if (_buffer == NULL) {
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return PEP_OUT_OF_MEMORY;
+ }
+
+ reading = _session->gpg.gpgme_data_read(plain, _buffer, length);
+ assert(length == reading);
+
+ gpgme_verify_result =
+ _session->gpg.gpgme_op_verify_result(_session->ctx);
+ assert(gpgme_verify_result);
+ gpgme_signature = gpgme_verify_result->signatures;
+
+ if (gpgme_signature) {
+ stringlist_t *k;
+ _keylist = new_stringlist(NULL);
+ assert(_keylist);
+ if (_keylist == NULL) {
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ free(_buffer);
+ return PEP_OUT_OF_MEMORY;
+ }
+ k = _keylist;
+
+ result = PEP_DECRYPTED_AND_VERIFIED;
+ do {
+ switch (gpgme_signature->status) {
+ case GPG_ERR_NO_ERROR:
+ k = stringlist_add(k, gpgme_signature->fpr);
+ break;
+ case GPG_ERR_CERT_REVOKED:
+ case GPG_ERR_BAD_SIGNATURE:
+ result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
+ break;
+ case GPG_ERR_SIG_EXPIRED:
+ case GPG_ERR_KEY_EXPIRED:
+ case GPG_ERR_NO_PUBKEY:
+ k = stringlist_add(k, gpgme_signature->fpr);
+ if (result == PEP_DECRYPTED_AND_VERIFIED)
+ result = PEP_DECRYPTED;
+ break;
+ case GPG_ERR_GENERAL:
+ break;
+ default:
+ if (result == PEP_DECRYPTED_AND_VERIFIED)
+ result = PEP_DECRYPTED;
+ break;
+ }
+ } while ((gpgme_signature = gpgme_signature->next));
+ }
+ else {
+ result = PEP_DECRYPTED;
+ }
+
+ if (result == PEP_DECRYPTED_AND_VERIFIED
+ || result == PEP_DECRYPTED) {
+ *ptext = _buffer;
+ *psize = reading;
+ (*ptext)[*psize] = 0; // safeguard for naive users
+ *keylist = _keylist;
+ }
+ else {
+ free_stringlist(_keylist);
+ free(_buffer);
+ }
+ break;
+ }
+ case GPG_ERR_DECRYPT_FAILED:
+ result = PEP_DECRYPT_WRONG_FORMAT;
+ break;
+ case GPG_ERR_BAD_PASSPHRASE:
+ NOT_IMPLEMENTED;
+ default:
+ {
+ gpgme_decrypt_result_t gpgme_decrypt_result = _session->gpg.gpgme_op_decrypt_result(_session->ctx);
+ result = PEP_DECRYPT_NO_KEY;
+
+ if (gpgme_decrypt_result != NULL) {
+ if (gpgme_decrypt_result->unsupported_algorithm)
+ *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
+ else
+ *keylist = new_stringlist("");
+ assert(*keylist);
+ if (*keylist == NULL) {
+ result = PEP_OUT_OF_MEMORY;
+ break;
+ }
+ stringlist_t *_keylist = *keylist;
+ for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
+ _keylist = stringlist_add(_keylist, r->keyid);
+ assert(_keylist);
+ if (_keylist == NULL) {
+ free_stringlist(*keylist);
+ *keylist = NULL;
+ result = PEP_OUT_OF_MEMORY;
+ break;
+ }
+ }
+ if (result == PEP_OUT_OF_MEMORY)
+ break;
+ }
+ }
+ }
+ break;
+
+ default:
+ result = PEP_DECRYPT_WRONG_FORMAT;
+ }
+
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return result;
+}
+
+PEP_STATUS pgp_verify_text(
+ PEP_SESSION session, const char *text, size_t size,
+ const char *signature, size_t sig_size, stringlist_t **keylist
+ )
+{
+ pEpSession *_session = (pEpSession *) session;
+
+ PEP_STATUS result;
+ gpgme_error_t gpgme_error;
+ gpgme_data_t d_text, d_sig;
+ stringlist_t *_keylist;
+
+ assert(session);
+ assert(text);
+ assert(size);
+ assert(signature);
+ assert(sig_size);
+ assert(keylist);
+
+ *keylist = NULL;
+
+ gpgme_error = _session->gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+ if (gpgme_error != GPG_ERR_NO_ERROR) {
+ if (gpgme_error == GPG_ERR_ENOMEM)
+ return PEP_OUT_OF_MEMORY;
+ else
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_error = _session->gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+ if (gpgme_error != GPG_ERR_NO_ERROR) {
+ _session->gpg.gpgme_data_release(d_text);
+ if (gpgme_error == GPG_ERR_ENOMEM)
+ return PEP_OUT_OF_MEMORY;
+ else
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_error = _session->gpg.gpgme_op_verify(_session->ctx, d_sig, d_text, NULL);
+ assert(gpgme_error != GPG_ERR_INV_VALUE);
+
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ {
+ gpgme_verify_result_t gpgme_verify_result;
+ gpgme_signature_t gpgme_signature;
+
+ gpgme_verify_result =
+ _session->gpg.gpgme_op_verify_result(_session->ctx);
+ assert(gpgme_verify_result);
+ gpgme_signature = gpgme_verify_result->signatures;
+
+ if (gpgme_signature) {
+ stringlist_t *k;
+ _keylist = new_stringlist(NULL);
+ assert(_keylist);
+ if (_keylist == NULL) {
+ _session->gpg.gpgme_data_release(d_text);
+ _session->gpg.gpgme_data_release(d_sig);
+ return PEP_OUT_OF_MEMORY;
+ }
+ k = _keylist;
+
+ result = PEP_VERIFIED;
+ do {
+ k = stringlist_add(k, gpgme_signature->fpr);
+ if (k == NULL) {
+ free_stringlist(_keylist);
+ _session->gpg.gpgme_data_release(d_text);
+ _session->gpg.gpgme_data_release(d_sig);
+ return PEP_OUT_OF_MEMORY;
+ }
+ if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
+ if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
+ || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
+ if (result == PEP_VERIFIED
+ || result == PEP_VERIFIED_AND_TRUSTED)
+ result = PEP_UNENCRYPTED;
+ }
+ else {
+ result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
+ break;
+ }
+ }
+ else {
+ if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
+ if (result == PEP_VERIFIED)
+ result = PEP_VERIFIED_AND_TRUSTED;
+ }
+ if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
+ // good
+ }
+ else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
+ result = PEP_VERIFY_NO_KEY;
+ }
+ else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
+ if (result == PEP_VERIFIED
+ || result == PEP_VERIFIED_AND_TRUSTED)
+ result = PEP_UNENCRYPTED;
+ }
+ else {
+ // do nothing
+ }
+ }
+ } while ((gpgme_signature = gpgme_signature->next));
+ *keylist = _keylist;
+ }
+ else {
+ result = PEP_UNENCRYPTED;
+ }
+ break;
+ }
+ break;
+ case GPG_ERR_NO_DATA:
+ result = PEP_DECRYPT_WRONG_FORMAT;
+ break;
+ case GPG_ERR_INV_VALUE:
+ default:
+ result = PEP_UNKNOWN_ERROR;
+ break;
+ }
+
+ _session->gpg.gpgme_data_release(d_text);
+ _session->gpg.gpgme_data_release(d_sig);
+
+ return result;
+}
+
+PEP_STATUS pgp_encrypt_and_sign(
+ PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
+ size_t psize, char **ctext, size_t *csize
+ )
+{
+ pEpSession *_session = (pEpSession *) session;
+
+ PEP_STATUS result;
+ gpgme_error_t gpgme_error;
+ gpgme_data_t plain, cipher;
+ gpgme_key_t *rcpt;
+ gpgme_encrypt_flags_t flags;
+ const stringlist_t *_keylist;
+ int i, j;
+
+ assert(_session);
+ assert(keylist);
+ assert(ptext);
+ assert(psize);
+ assert(ctext);
+ assert(csize);
+
+ *ctext = NULL;
+ *csize = 0;
+
+ gpgme_error = _session->gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+ if (gpgme_error != GPG_ERR_NO_ERROR) {
+ if (gpgme_error == GPG_ERR_ENOMEM)
+ return PEP_OUT_OF_MEMORY;
+ else
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_error = _session->gpg.gpgme_data_new(&cipher);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+ if (gpgme_error != GPG_ERR_NO_ERROR) {
+ _session->gpg.gpgme_data_release(plain);
+ if (gpgme_error == GPG_ERR_ENOMEM)
+ return PEP_OUT_OF_MEMORY;
+ else
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ rcpt = (gpgme_key_t *) calloc(stringlist_length(keylist) + 1,
+ sizeof(gpgme_key_t));
+ assert(rcpt);
+ if (rcpt == NULL) {
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return PEP_OUT_OF_MEMORY;
+ }
+
+ _session->gpg.gpgme_signers_clear(_session->ctx);
+
+ for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
+ assert(_keylist->value);
+ gpgme_error = _session->gpg.gpgme_get_key(_session->ctx, _keylist->value,
+ &rcpt[i], 0);
+ assert(gpgme_error != GPG_ERR_ENOMEM);
+
+ switch (gpgme_error) {
+ case GPG_ERR_ENOMEM:
+ for (j = 0; jgpg.gpgme_key_unref(rcpt[j]);
+ free(rcpt);
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return PEP_OUT_OF_MEMORY;
+ case GPG_ERR_NO_ERROR:
+ if (i == 0) {
+ gpgme_error_t _gpgme_error = _session->gpg.gpgme_signers_add(_session->ctx, rcpt[0]);
+ assert(_gpgme_error == GPG_ERR_NO_ERROR);
+ }
+ break;
+ case GPG_ERR_EOF:
+ for (j = 0; jgpg.gpgme_key_unref(rcpt[j]);
+ free(rcpt);
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return PEP_KEY_NOT_FOUND;
+ case GPG_ERR_AMBIGUOUS_NAME:
+ for (j = 0; jgpg.gpgme_key_unref(rcpt[j]);
+ free(rcpt);
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return PEP_KEY_HAS_AMBIG_NAME;
+ default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
+ // FPR is not a fingerprint or key ID
+ for (j = 0; jgpg.gpgme_key_unref(rcpt[j]);
+ free(rcpt);
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return PEP_GET_KEY_FAILED;
+ }
+ }
+
+ // TODO: remove that and replace with proper key management
+ flags = GPGME_ENCRYPT_ALWAYS_TRUST;
+
+ gpgme_error = _session->gpg.gpgme_op_encrypt_sign(_session->ctx, rcpt, flags,
+ plain, cipher);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ {
+ char *_buffer = NULL;
+ size_t reading;
+ size_t length = _session->gpg.gpgme_data_seek(cipher, 0, SEEK_END);
+ assert(length != -1);
+ _session->gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
+
+ // TODO: make things less memory consuming
+ // the following algorithm allocates a buffer for the complete text
+
+ _buffer = (char *) malloc(length + 1);
+ assert(_buffer);
+ if (_buffer == NULL) {
+ for (j = 0; jgpg.gpgme_key_unref(rcpt[j]);
+ free(rcpt);
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return PEP_OUT_OF_MEMORY;
+ }
+
+ reading = _session->gpg.gpgme_data_read(cipher, _buffer, length);
+ assert(length == reading);
+
+ *ctext = _buffer;
+ *csize = reading;
+ (*ctext)[*csize] = 0; // safeguard for naive users
+ result = PEP_STATUS_OK;
+ break;
+ }
+ default:
+ result = PEP_UNKNOWN_ERROR;
+ }
+
+ for (j = 0; jgpg.gpgme_key_unref(rcpt[j]);
+ free(rcpt);
+ _session->gpg.gpgme_data_release(plain);
+ _session->gpg.gpgme_data_release(cipher);
+ return result;
+}
+
+PEP_STATUS pgp_generate_keypair(
+ PEP_SESSION session, pEp_identity *identity
+ )
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+ char *parms;
+ const char *template =
+ "\n"
+ "Key-Type: RSA\n"
+ "Key-Length: 4096\n"
+ "Name-Real: %s\n"
+ "Name-Email: %s\n"
+ /* "Passphrase: %s\n" */
+ "Expire-Date: 1y\n"
+ "\n";
+ int result;
+ gpgme_genkey_result_t gpgme_genkey_result;
+
+ assert(session);
+ assert(identity);
+ assert(identity->address);
+ assert(identity->fpr == NULL);
+ assert(identity->username);
+
+ parms = calloc(1, PARMS_MAX);
+ assert(parms);
+ if (parms == NULL)
+ return PEP_OUT_OF_MEMORY;
+
+ result = snprintf(parms, PARMS_MAX, template, identity->username,
+ identity->address); // , _session->passphrase);
+ assert(result < PARMS_MAX);
+ if (result >= PARMS_MAX) {
+ free(parms);
+ return PEP_BUFFER_TOO_SMALL;
+ }
+
+ gpgme_error = _session->gpg.gpgme_op_genkey(_session->ctx, parms, NULL, NULL);
+ free(parms);
+
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_INV_VALUE:
+ return PEP_ILLEGAL_VALUE;
+ case GPG_ERR_GENERAL:
+ return PEP_CANNOT_CREATE_KEY;
+ default:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_genkey_result = _session->gpg.gpgme_op_genkey_result(_session->ctx);
+ assert(gpgme_genkey_result);
+ assert(gpgme_genkey_result->fpr);
+
+ identity->fpr = strdup(gpgme_genkey_result->fpr);
+
+ return PEP_STATUS_OK;
+}
+
+PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+ gpgme_key_t key;
+
+ assert(session);
+ assert(fpr);
+
+ gpgme_error = _session->gpg.gpgme_get_key(_session->ctx, fpr, &key, 0);
+ assert(gpgme_error != GPG_ERR_ENOMEM);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_EOF:
+ return PEP_KEY_NOT_FOUND;
+ case GPG_ERR_INV_VALUE:
+ return PEP_ILLEGAL_VALUE;
+ case GPG_ERR_AMBIGUOUS_NAME:
+ return PEP_KEY_HAS_AMBIG_NAME;
+ case GPG_ERR_ENOMEM:
+ return PEP_OUT_OF_MEMORY;
+ default:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_error = _session->gpg.gpgme_op_delete(_session->ctx, key, 1);
+ _session->gpg.gpgme_key_unref(key);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ case GPG_ERR_NO_PUBKEY:
+ assert(0);
+ return PEP_KEY_NOT_FOUND;
+ case GPG_ERR_AMBIGUOUS_NAME:
+ assert(0);
+ return PEP_KEY_HAS_AMBIG_NAME;
+ default:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ return PEP_STATUS_OK;
+}
+
+PEP_STATUS pgp_import_key(PEP_SESSION session, const char *key_data, size_t size)
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+ gpgme_data_t dh;
+
+ assert(session);
+ assert(key_data);
+
+ gpgme_error = _session->gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
+ assert(gpgme_error != GPG_ERR_ENOMEM);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_ENOMEM:
+ return PEP_OUT_OF_MEMORY;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ default:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_error = _session->gpg.gpgme_op_import(_session->ctx, dh);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_UNKNOWN_ERROR;
+ case GPG_ERR_NO_DATA:
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_ILLEGAL_VALUE;
+ default:
+ assert(0);
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_STATUS_OK;
+}
+
+PEP_STATUS pgp_export_key(
+ PEP_SESSION session, const char *fpr, char **key_data, size_t *size
+ )
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+ gpgme_data_t dh;
+ size_t _size;
+ char *buffer;
+ int reading;
+
+ assert(session);
+ assert(fpr);
+ assert(key_data);
+ assert(size);
+
+ gpgme_error = _session->gpg.gpgme_data_new(&dh);
+ assert(gpgme_error != GPG_ERR_ENOMEM);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_ENOMEM:
+ return PEP_OUT_OF_MEMORY;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ default:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ }
+
+ gpgme_error = _session->gpg.gpgme_op_export(_session->ctx, fpr,
+ GPGME_EXPORT_MODE_MINIMAL, dh);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_EOF:
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_KEY_NOT_FOUND;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_UNKNOWN_ERROR;
+ default:
+ assert(0);
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_UNKNOWN_ERROR;
+ };
+
+ _size = _session->gpg.gpgme_data_seek(dh, 0, SEEK_END);
+ assert(_size != -1);
+ _session->gpg.gpgme_data_seek(dh, 0, SEEK_SET);
+
+ buffer = malloc(_size + 1);
+ assert(buffer);
+ if (buffer == NULL) {
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_OUT_OF_MEMORY;
+ }
+
+ reading = _session->gpg.gpgme_data_read(dh, buffer, _size);
+ assert(_size == reading);
+
+ // safeguard for the naive user
+ buffer[_size] = 0;
+
+ *key_data = buffer;
+ *size = _size;
+
+ _session->gpg.gpgme_data_release(dh);
+ return PEP_STATUS_OK;
+}
+
+static void _switch_mode(pEpSession *_session, gpgme_keylist_mode_t remove_mode,
+ gpgme_keylist_mode_t add_mode)
+{
+ gpgme_error_t gpgme_error;
+ gpgme_keylist_mode_t mode;
+
+ mode = _session->gpg.gpgme_get_keylist_mode(_session->ctx);
+
+ mode &= ~remove_mode;
+ mode |= add_mode;
+
+ gpgme_error = _session->gpg.gpgme_set_keylist_mode(_session->ctx, mode);
+ assert(gpgme_error == GPG_ERR_NO_ERROR);
+}
+
+PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+ gpgme_key_t key;
+
+ assert(session);
+ assert(pattern);
+
+ _switch_mode(_session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
+
+ gpgme_error = _session->gpg.gpgme_op_keylist_start(_session->ctx, pattern, 0);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
+ GPGME_KEYLIST_MODE_LOCAL);
+ return PEP_UNKNOWN_ERROR;
+ default:
+ _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
+ GPGME_KEYLIST_MODE_LOCAL);
+ return PEP_GET_KEY_FAILED;
+ };
+
+ do {
+ gpgme_error = _session->gpg.gpgme_op_keylist_next(_session->ctx, &key);
+ assert(gpgme_error != GPG_ERR_INV_VALUE);
+ switch (gpgme_error) {
+ case GPG_ERR_EOF:
+ break;
+ case GPG_ERR_NO_ERROR:
+ {
+ gpgme_error_t gpgme_error;
+ gpgme_key_t keys[2];
+
+ keys[0] = key;
+ keys[1] = NULL;
+
+ gpgme_error = _session->gpg.gpgme_op_import_keys(_session->ctx, keys);
+ _session->gpg.gpgme_key_unref(key);
+ assert(gpgme_error != GPG_ERR_INV_VALUE);
+ assert(gpgme_error != GPG_ERR_CONFLICT);
+ }
+ break;
+ case GPG_ERR_ENOMEM:
+ _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
+ GPGME_KEYLIST_MODE_LOCAL);
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+ return PEP_OUT_OF_MEMORY;
+ default:
+ // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
+ // reading first key
+#ifndef NDEBUG
+ fprintf(stderr, "warning: unknown result 0x%x of"
+ " gpgme_op_keylist_next()\n", gpgme_error);
+#endif
+ gpgme_error = GPG_ERR_EOF;
+ break;
+ };
+ } while (gpgme_error != GPG_ERR_EOF);
+
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+ _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
+ GPGME_KEYLIST_MODE_LOCAL);
+ return PEP_STATUS_OK;
+}
+
+PEP_STATUS pgp_find_keys(
+ PEP_SESSION session, const char *pattern, stringlist_t **keylist
+ )
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+ gpgme_key_t key;
+ stringlist_t *_keylist;
+ char *fpr;
+
+ assert(session);
+ assert(pattern);
+ assert(keylist);
+
+ *keylist = NULL;
+
+ gpgme_error = _session->gpg.gpgme_op_keylist_start(_session->ctx, pattern, 0);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ default:
+ return PEP_GET_KEY_FAILED;
+ };
+
+ _keylist = new_stringlist(NULL);
+ stringlist_t *_k = _keylist;
+
+ do {
+ gpgme_error = _session->gpg.gpgme_op_keylist_next(_session->ctx, &key);
+ assert(gpgme_error != GPG_ERR_INV_VALUE);
+ switch (gpgme_error) {
+ case GPG_ERR_EOF:
+ break;
+ case GPG_ERR_NO_ERROR:
+ assert(key);
+ assert(key->subkeys);
+ fpr = key->subkeys->fpr;
+ assert(fpr);
+ _k = stringlist_add(_k, fpr);
+ assert(_k);
+ if (_k != NULL)
+ break;
+ case GPG_ERR_ENOMEM:
+ free_stringlist(_keylist);
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+ return PEP_OUT_OF_MEMORY;
+ default:
+ // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
+ // reading first key
+#ifndef NDEBUG
+ fprintf(stderr, "warning: unknown result 0x%x of"
+ " gpgme_op_keylist_next()\n", gpgme_error);
+#endif
+ gpgme_error = GPG_ERR_EOF;
+ break;
+ };
+ } while (gpgme_error != GPG_ERR_EOF);
+
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+ *keylist = _keylist;
+ return PEP_STATUS_OK;
+}
+
+PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
+{
+ pEpSession *_session = (pEpSession *) session;
+ gpgme_error_t gpgme_error;
+
+ assert(session);
+ assert(pattern);
+
+ gpgme_error = _session->gpg.gpgme_op_export(_session->ctx, pattern,
+ GPGME_EXPORT_MODE_EXTERN, NULL);
+ assert(gpgme_error != GPG_ERR_INV_VALUE);
+ if (gpgme_error == GPG_ERR_NO_ERROR)
+ return PEP_STATUS_OK;
+ else
+ return PEP_CANNOT_SEND_KEY;
+}
+
+
+PEP_STATUS pgp_get_key_rating(
+ PEP_SESSION session,
+ const char *fpr,
+ PEP_comm_type *comm_type
+ )
+{
+ pEpSession *_session = (pEpSession *) session;
+ PEP_STATUS status = PEP_STATUS_OK;
+ gpgme_error_t gpgme_error;
+ gpgme_key_t key;
+
+ assert(session);
+ assert(fpr);
+ assert(comm_type);
+
+ *comm_type = PEP_ct_unknown;
+
+ gpgme_error = _session->gpg.gpgme_op_keylist_start(_session->ctx, fpr, 0);
+ switch (gpgme_error) {
+ case GPG_ERR_NO_ERROR:
+ break;
+ case GPG_ERR_INV_VALUE:
+ assert(0);
+ return PEP_UNKNOWN_ERROR;
+ default:
+ return PEP_GET_KEY_FAILED;
+ };
+
+ gpgme_error = _session->gpg.gpgme_op_keylist_next(_session->ctx, &key);
+ assert(gpgme_error != GPG_ERR_INV_VALUE);
+
+ if (key == NULL) {
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+ return PEP_KEY_NOT_FOUND;
+ }
+
+ switch (key->protocol) {
+ case GPGME_PROTOCOL_OpenPGP:
+ case GPGME_PROTOCOL_DEFAULT:
+ *comm_type = PEP_ct_OpenPGP_unconfirmed;
+ break;
+ case GPGME_PROTOCOL_CMS:
+ *comm_type = PEP_ct_CMS_unconfirmed;
+ break;
+ default:
+ *comm_type = PEP_ct_unknown;
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+ return PEP_STATUS_OK;
+ }
+
+ switch (gpgme_error) {
+ case GPG_ERR_EOF:
+ break;
+ case GPG_ERR_NO_ERROR:
+ assert(key);
+ assert(key->subkeys);
+ for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
+ if (sk->length < 1024)
+ *comm_type = PEP_ct_key_too_short;
+ else if (
+ (
+ (sk->pubkey_algo == GPGME_PK_RSA)
+ || (sk->pubkey_algo == GPGME_PK_RSA_E)
+ || (sk->pubkey_algo == GPGME_PK_RSA_S)
+ )
+ && sk->length == 1024
+ )
+ *comm_type = PEP_ct_OpenPGP_1024_RSA_unconfirmed;
+
+ if (sk->invalid) {
+ *comm_type = PEP_ct_key_b0rken;
+ break;
+ }
+ if (sk->expired) {
+ *comm_type = PEP_ct_key_expired;
+ break;
+ }
+ if (sk->revoked) {
+ *comm_type = PEP_ct_key_revoked;
+ break;
+ }
+ }
+ break;
+ case GPG_ERR_ENOMEM:
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+ *comm_type = PEP_ct_unknown;
+ return PEP_OUT_OF_MEMORY;
+ default:
+ // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
+ // reading first key
+#ifndef NDEBUG
+ fprintf(stderr, "warning: unknown result 0x%x of"
+ " gpgme_op_keylist_next()\n", gpgme_error);
+#endif
+ gpgme_error = GPG_ERR_EOF;
+ break;
+ };
+
+ _session->gpg.gpgme_op_keylist_end(_session->ctx);
+
+ return status;
+}
diff --git a/src/pgp_gpg.h b/src/pgp_gpg.h
new file mode 100644
index 00000000..e10c731a
--- /dev/null
+++ b/src/pgp_gpg.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "pEpEngine.h"
+
+PEP_STATUS pgp_init(PEP_SESSION session);
+void pgp_release(PEP_SESSION session);
+
+PEP_STATUS pgp_decrypt_and_verify(
+ PEP_SESSION session, const char *ctext, size_t csize,
+ char **ptext, size_t *psize, stringlist_t **keylist
+ );
+
+PEP_STATUS pgp_encrypt_and_sign(
+ PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
+ size_t psize, char **ctext, size_t *csize
+ );
+
+PEP_STATUS pgp_verify_text(
+ PEP_SESSION session, const char *text, size_t size,
+ const char *signature, size_t sig_size, stringlist_t **keylist
+ );
+
+PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr);
+
+PEP_STATUS pgp_export_key(
+ PEP_SESSION session, const char *fpr, char **key_data, size_t *size
+ );
+
+PEP_STATUS pgp_find_keys(
+ PEP_SESSION session, const char *pattern, stringlist_t **keylist
+ );
+
+PEP_STATUS pgp_generate_keypair(
+ PEP_SESSION session, pEp_identity *identity
+ );
+
+PEP_STATUS pgp_get_key_rating(
+ PEP_SESSION session,
+ const char *fpr,
+ PEP_comm_type *comm_type
+ );
+
+PEP_STATUS pgp_import_key(PEP_SESSION session, const char *key_data, size_t size);
+
+PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern);
+
+PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern);
diff --git a/src/pgp_gpg_internal.h b/src/pgp_gpg_internal.h
new file mode 100644
index 00000000..9c6a1638
--- /dev/null
+++ b/src/pgp_gpg_internal.h
@@ -0,0 +1,106 @@
+#include
+
+// init
+
+typedef const char * (*gpgme_check_version_t)(const char*);
+typedef gpgme_error_t(*gpgme_set_locale_t)(gpgme_ctx_t CTX, int CATEGORY,
+ const char *VALUE);
+typedef gpgme_error_t(*gpgme_new_t)(gpgme_ctx_t *CTX);
+typedef void(*gpgme_release_t)(gpgme_ctx_t CTX);
+typedef gpgme_error_t(*gpgme_set_protocol_t)(gpgme_ctx_t CTX,
+ gpgme_protocol_t PROTO);
+typedef void(*gpgme_set_armor_t)(gpgme_ctx_t CTX, int YES);
+
+// data
+
+typedef gpgme_error_t(*gpgme_data_new_t)(gpgme_data_t *DH);
+typedef gpgme_error_t(*gpgme_data_new_from_mem_t)(gpgme_data_t *DH,
+ const char *BUFFER, size_t SIZE, int COPY);
+typedef void(*gpgme_data_release_t)(gpgme_data_t DH);
+typedef gpgme_data_type_t(*gpgme_data_identify_t)(gpgme_data_t DH);
+typedef size_t(*gpgme_data_seek_t)(gpgme_data_t DH, size_t OFFSET,
+ int WHENCE);
+typedef size_t(*gpgme_data_read_t)(gpgme_data_t DH, void *BUFFER,
+ size_t LENGTH);
+
+// encrypt and decrypt
+
+typedef gpgme_error_t(*gpgme_op_decrypt_t)(gpgme_ctx_t CTX,
+ gpgme_data_t CIPHER, gpgme_data_t PLAIN);
+typedef gpgme_error_t(*gpgme_op_verify_t)(gpgme_ctx_t CTX, gpgme_data_t SIG,
+ gpgme_data_t SIGNED_TEXT, gpgme_data_t PLAIN);
+typedef gpgme_error_t(*gpgme_op_decrypt_verify_t)(gpgme_ctx_t CTX,
+ gpgme_data_t CIPHER, gpgme_data_t PLAIN);
+typedef gpgme_decrypt_result_t(*gpgme_op_decrypt_result_t)(gpgme_ctx_t CTX);
+typedef gpgme_error_t(*gpgme_op_encrypt_sign_t)(gpgme_ctx_t CTX,
+ gpgme_key_t RECP[], gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
+ gpgme_data_t CIPHER);
+typedef gpgme_verify_result_t(*gpgme_op_verify_result_t)(gpgme_ctx_t CTX);
+typedef void(*gpgme_signers_clear_t)(gpgme_ctx_t CTX);
+typedef gpgme_error_t(*gpgme_signers_add_t)(gpgme_ctx_t CTX, const gpgme_key_t KEY);
+
+// keys
+
+typedef gpgme_error_t(*gpgme_get_key_t)(gpgme_ctx_t CTX, const char *FPR,
+ gpgme_key_t *R_KEY, int SECRET);
+typedef gpgme_error_t(*gpgme_op_genkey_t)(gpgme_ctx_t CTX, const char *PARMS,
+ gpgme_data_t PUBLIC, gpgme_data_t SECRET);
+typedef gpgme_genkey_result_t(*gpgme_op_genkey_result_t)(gpgme_ctx_t CTX);
+typedef gpgme_error_t(*gpgme_op_delete_t)(gpgme_ctx_t CTX,
+ const gpgme_key_t KEY, int ALLOW_SECRET);
+typedef gpgme_error_t(*gpgme_op_import_t)(gpgme_ctx_t CTX,
+ gpgme_data_t KEYDATA);
+typedef gpgme_error_t(*gpgme_op_export_t)(gpgme_ctx_t CTX,
+ const char *PATTERN, gpgme_export_mode_t MODE, gpgme_data_t KEYDATA);
+typedef gpgme_error_t(*gpgme_set_keylist_mode_t)(gpgme_ctx_t CTX,
+ gpgme_keylist_mode_t MODE);
+typedef gpgme_keylist_mode_t(*gpgme_get_keylist_mode_t)(gpgme_ctx_t CTX);
+typedef gpgme_error_t(*gpgme_op_keylist_start_t)(gpgme_ctx_t CTX,
+ const char *PATTERN, int SECRET_ONLY);
+typedef gpgme_error_t(*gpgme_op_keylist_next_t)(gpgme_ctx_t CTX,
+ gpgme_key_t *R_KEY);
+typedef gpgme_error_t(*gpgme_op_keylist_end_t)(gpgme_ctx_t CTX);
+typedef gpgme_error_t(*gpgme_op_import_keys_t)(gpgme_ctx_t CTX,
+ gpgme_key_t *KEYS);
+typedef void(*gpgme_key_ref_t)(gpgme_key_t KEY);
+typedef void(*gpgme_key_unref_t)(gpgme_key_t KEY);
+
+struct gpg_s {
+ gpgme_check_version_t gpgme_check;
+ gpgme_set_locale_t gpgme_set_locale;
+ gpgme_new_t gpgme_new;
+ gpgme_release_t gpgme_release;
+ gpgme_set_protocol_t gpgme_set_protocol;
+ gpgme_set_armor_t gpgme_set_armor;
+
+ gpgme_data_new_t gpgme_data_new;
+ gpgme_data_new_from_mem_t gpgme_data_new_from_mem;
+ gpgme_data_release_t gpgme_data_release;
+ gpgme_data_identify_t gpgme_data_identify;
+ gpgme_data_seek_t gpgme_data_seek;
+ gpgme_data_read_t gpgme_data_read;
+
+ gpgme_op_decrypt_t gpgme_op_decrypt;
+ gpgme_op_verify_t gpgme_op_verify;
+ gpgme_op_decrypt_verify_t gpgme_op_decrypt_verify;
+ gpgme_op_decrypt_result_t gpgme_op_decrypt_result;
+ gpgme_op_encrypt_sign_t gpgme_op_encrypt_sign;
+ gpgme_op_verify_result_t gpgme_op_verify_result;
+ gpgme_signers_clear_t gpgme_signers_clear;
+ gpgme_signers_add_t gpgme_signers_add;
+
+ gpgme_get_key_t gpgme_get_key;
+ gpgme_op_genkey_t gpgme_op_genkey;
+ gpgme_op_genkey_result_t gpgme_op_genkey_result;
+ gpgme_op_delete_t gpgme_op_delete;
+ gpgme_op_import_t gpgme_op_import;
+ gpgme_op_export_t gpgme_op_export;
+ gpgme_set_keylist_mode_t gpgme_set_keylist_mode;
+ gpgme_get_keylist_mode_t gpgme_get_keylist_mode;
+ gpgme_op_keylist_start_t gpgme_op_keylist_start;
+ gpgme_op_keylist_next_t gpgme_op_keylist_next;
+ gpgme_op_keylist_end_t gpgme_op_keylist_end;
+ gpgme_op_import_keys_t gpgme_op_import_keys;
+ gpgme_key_ref_t gpgme_key_ref;
+ gpgme_key_unref_t gpgme_key_unref;
+};
diff --git a/src/platform_windows.h b/src/platform_windows.h
index 64eaca0f..fb768172 100644
--- a/src/platform_windows.h
+++ b/src/platform_windows.h
@@ -9,8 +9,7 @@
#ifndef snprintf
#define snprintf _snprintf
#endif
-#define _CRT_NONSTDC_NO_DEPRECATE
-#define _CRT_SECURE_NO_WARNINGS
+#pragma warning(disable : 4996)
#ifdef __cplusplus
extern "C" {