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" {