From 4b94f3c410b8bd601994788749a240f0917e43dc Mon Sep 17 00:00:00 2001 From: vb Date: Mon, 1 Sep 2014 17:44:19 +0200 Subject: [PATCH] ... --- pEpEngine.vcxproj | 4 + pEpEngine.vcxproj.filters | 12 + src/cryptotech.c | 24 +- src/cryptotech.h | 45 +- src/gpgme.exp | Bin 0 -> 23236 bytes src/gpgme.lib | Bin 0 -> 38658 bytes src/keymanagement.c | 3 + src/pEpEngine.c | 1447 +++---------------------------------- src/pEp_internal.h | 80 ++ src/pgp_gpg.c | 1202 ++++++++++++++++++++++++++++++ src/pgp_gpg.h | 47 ++ src/pgp_gpg_internal.h | 106 +++ src/platform_windows.h | 3 +- 13 files changed, 1601 insertions(+), 1372 deletions(-) create mode 100644 src/gpgme.exp create mode 100644 src/gpgme.lib create mode 100644 src/pEp_internal.h create mode 100644 src/pgp_gpg.c create mode 100644 src/pgp_gpg.h create mode 100644 src/pgp_gpg_internal.h 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 0000000000000000000000000000000000000000..e62d12109ffbf70e2e181d24f4e6ab9b456b8dd6 GIT binary patch literal 23236 zcmeI4eY_OadB-2#TtrYVf}#RmiV3ZxwF!x~H4SY@LM>@XYZ8*slqS^BlvdIhYZH=^q`&8xnVs`8>p%V1 z`M}{h-{+Y#=bSln=InVMX7PZ5)VFHzvZqo+iv|!M17;NRxmr$SNq&1aQ6ADgqdm3| zc60G(M!vAJuXEC^9wq9B{``xAocHfs8aa<8zDA(o%e?IW4cLeOe%J#a_P~cd@L>-S zwa`b=4Uf#3LSqhVB~opc5brxA1}okb(5iE=cG&Zg0{lE%v1^XTKWnRd`N>ZC4m zDM8(IFU9Es`WS7ZCut+4DMK6RVQQtBbS2HA*))f)!aLwlju?U1Wl$gJx^2U5}HcW=u&!tE~Dx63|&rrRHM~2gRY>L$e|bwrPHZMJ(Q#p zrDz3hrOw{Yp2CcLvFJ(J_FSpGpl7nV>e^C!pzkWQugb12RI1(OQWVQ}muiJdDOWF} zTP^C~TWVYM6Pv zBOi@%y@rb3T%{JN>?!m_@@lP8$XTlX?pjwCiaaW(p2kSetM@^g<@b0tSISGb85gb; z`nyY78P!5zm0G5E8|=Pj9@*FZmF`;5BmSLjj~Hx)N+pX@3ts0UR|;;vuBooA0+cI$ zo$AV3IcuKOlUvoGIBA4_iE_ohaz~{Q)SSm`qb8Vu!5&Do2zM^!kWHf zIYQC5GTUocq*ho{QySfst9E5`#m=%?vF@@w6MnxSr;fZJ8_aF!SMPrJbqB+pkuY@fxqu|7*d-JYxDvxR)Oaz-6lw)_Stmg}<+pU$Y7TOEv7pnRddvbI+# z&j(g}0&dhOz<67Qb9h)Tzs11Ky5;dws!v2>&3V&GZz$(1i;_|Mf(NYH2OPIJ7nZn@lQu^afAwANEosa(C)3Vi zd1bDc?I`Agfy*@NWf4MQSWcz5$|u|*8AJ1>ie5f)qa~Y zHr}QfFWFKVFK;aUv$=dQ1U1}_*IKZu(G+-${aJyB9ezLPB?vK2_Ly?dgEI@IzF@7( z3twfK7i6>bI@BuFa$luAc&*5Q&0?k5BQIP0SW%Z8h8Cq6YZApE96B0QU+aoO9asIi z`b&~UnXiW9ckDp?jp3Il;kPME%}57}GzsYtk?=E>UJ>b4n4cz+18KKNdmzO`nu_#u zBE1eaRHV6({zRlVAe}DKI7ojg(q2fzL~4fgs!01FogvaBNPi~Men?!~7>$MWd65o4 z8X?kg)b9%-9Rxd5q!VC!M0yMCERmKX{h~;Rz($JnKJ30E(qXVBk#<9RO{61`Mv27R zqpyo}6bxIgsLOJse=gE7Fl?`awITfrk&c6n5ora|zZB^N*f}Ecj_n&Fy$g1(NL@(3 zEYka6V?`<={VS19f}JPQtElr=L^=g_zDT`D_lm?f@&b`+NdH=-!C-ukW7usV`Wumk zf{hnx56b(hNW;MJOB9S&C{f0>6z%CZa zLAqb0X0VAOC6WHENRz;Lyv1k>TJ)w!Q^6*SltKD;B25RIBGN3R2SjqfE)i)f&i$rH zNiZIbF`A3???uXhO%rJ_?7k(^EU-&O+K%*~NOQq16KOiqZ;Lb^jB_y>j&uJ(q(xwt zi!>DMA4OUWHbbNxNZ%4^DcBVv?L_(=k(PmRkHlyN`tQ3UEeCT&+J*FcBDI0VMcR$@ zkVq@Q5+d!yb-yoC9*lc4CeP3hMCt;A+W>42(jSUc1Zxp#Gt$E%^@62E+K0OQlSnl% z?)4bG4)!CF)_}E&^aj{Ji?kkWrbv6ij)=4Y>`G5U{r*LyjbMDoP#)4Bi?kVRwn$r$ z{=}2O=7=;O=N=VlE7(;cEdu*jk+y-&6=^%z+nxk=wMc8gek#%quz4cwNBxe8v=i(a zkq&_Un@GFB=8JR!>CZ&k4Yoj}_mTd)NUwq|6zL$&JucE7uxmwn3+z8cdL3+$Nbe&3 zPm$gLyH2ESNZ%1@FWB`WB~fR-c8vCc-5}B|u%C;xA8fHmd9eQy=>XV`B4xmSA<{vx zB_a(*UHIBDdJF6(k%of(Qlvv*OGTQBbKeu`Fxbr^O$YmLk&b}fBGPc2%l#0eqhPm+ zG!pE8L^=kxOr+6ZzY^&<*li+>1^cx~C%|qOX&l%|k=_NnL!@S~--z@+*m993f&Esb zlVEp>G!^WBMLGrc5s{{Yof3&(Uw4V*fc;LS!C-A7CBc3#(onFwMaqEvL8Ree_lPtL zjPN%`Bf+x5<|02p*l4g7!sa7CP}o?ooUld64-z&GY^AWp$n!nH8y2ixSR49zh_Fdu zd0{KSP7^j2tRQSD=Y>rN>kzgKdA^@9a=Zd6<}3iYmgr!EDu%_wjTL&gmr=S3EP1D zxx$KItA%Yw{dio)s28kX*haAPgw?>-cntaTg{=Ww>z#}I1;W;YtrNBdc^=a-+5mRH zu&v0C7q$^>y|8V_PY|{l>;Ylhk-t#b7O)3}?LfX+*jBKIgzZHBB4OLWHVE5={Kdky zgFP&)hIUL8wgc>=!g|3b3EK(wF=0ip$-;JlZ4|Z@=@enR!8Qqd1L-BgUIlwZ*kYW^ z&mrC}U>_H@6l|KX*TMJ=6O%Q`rNZ6-dsNslR@u(!aT6!sQUSJ)viZfT5m;JR^Phryl_b_i)g z*b%T#3OkH6DeNfN)56x{+?23mVB3TpLE0khIM_47P9dKbb^`2E!cHQe5%w=f8@!gk@@S;BbH{=Bf`NM{Qh47Nkqe57-P4F!8a z*dnA?2^$XfqA-5j%oR2g>?L7`k-u8lXt15ajvzlz*jTWag`Grtjj(ZGpAmKx`T4?{ z!9FYO6w(F4CV}k|wi|hlV2IIFus;&kg|=NQY&zH<3q!-@U3T(pUdaz=Le~4KHv`*8 zSij9`ih&GbEXQ!9lku3}*xg=Bc+#YhHZak{d7(W;aoLf1a+H*>)Q?@T+aB zSGLVBxA*m6gSy&wdpGtoi_N#zuuD{KjyrCmZE2-^Z=oH!-UYo2#39sHt+Z2NO@YgR zwzHD!X;mWpC_2rFF$v0#H&BMIGcNu?#VT-^@#gLX=pKsD1^XN0q2FNW6|Wi> z{eYnkPQ3`a`xIS-pN&l_x(V+TsIIsRVRA-jQunZ7N7M7XHN&75VGz27xC>u4Eb6|v zbD$hTW}B z$&d)Ey8n=`bee8pIudypKd+m}!y+C<9*tPh2BS@Ou~gUMDCpOOdhs!GzmE?YyNkRH zN`B}E>I(Id~hK@*lgj@ zSIJkrNZ0F|o^0@vVW91Pa!*`r7%1DI{9sJ9)ZTt5mwjHe&hsDg6Va&~@E#{Oj5{)K ztFSB1u1+2+g(z*fzsQqMhi#(x`*^^7+OSafZMkWabbWmTm#cSvs5AVce6u!(+Q31| z6YZlK_MSr?O)uEIgzc|P(=(xhci|;8f_dWx1(62q6~QiUrfFeAwSRf;(rcrQ#Fx)qu}If@ zE@f`ibrA{~f&64&-$3bKn5Um7qD(MFRAo8zWFxI#0yqDLC>w7uaLpHMYTpsfO};Tg zp?2$%D7{xMSA4ypuDhe9;`cYw`W5GzE!Av1S2FwpnWkcdLi&`iyCq6l@36-kX_b3@ zbCiwmg5?gqB}yMQ{8mkkE7$$Pyb@a$t*tw~`2x2^+K3C82mI}kYQKVf=kAC!2ygkb zn%;Me^M$uZDEyA$=XSZKmIsJ?{7wr8!-Q|vM{KQE6Rzo9no=Bp_1@y9wl&a8U+}x& z?gj>7WAD){{7H_losCcg73a=a5vBLa<#uh;)uHd5C-$c;rRRj_hyIh%y5Q1WwF^QM z%Pr40VsfYteuVNI`3V(s>=MfCkmbc=md1Mn^J6w8)bTPqTp9Q33Uy`7{j)}CU}Iz&(H0=RM-0sf4=Bty2f4vzi1d(i{R;ofw2g_+){gs zV6OJ3be$F*z=L9juCK2$`P|it&Wsn}ao*QJ@A>|@g#HE=96`V1g5mWQuRdp<1or2T(4_S*b_bu@5pd%34~Mt6R4{}K8Fd`5#v z{qI;@kwH{lw}eBwsdAcEwLw(r>}9WmxTHOsN~dS_Dz-KQ(tlGWk4hNAJZVMH4(&Ex4jW}+co;654yWEsZ%^GnMEtJ*?p400!;=(3tkTmt^B$cN1I!U(D7M)lii?R9>onX|xrx7QWp&=vmR*cE zf)rgaEX`Mmh^prso z^ol`}wAUbbHyNaber}L74H>Dn!c8S;oI&C=T_a8=L-P#MN=tRp>QKQTF0D04oVFSS z?_7f<>1zf_(RU2eLdP}YCNuPVgQRH`+_d2=;U-&XvPPVEny%7GB2Bkz#7$%xRI&9^Nkp@09a& zg6C_xL0aibowyDy)`;t1Wu+6?tkZ~tr{H;wxL8&0(TIc9&Np?^iZ!i9++>R0sS{p< zbKpR5VDXIu&8{CFnNrVt0n%PTV*ouH4n+$NkMsmt{OgfT7U3X_;P7nr1X=v+k#AY# zXBNRvkNV-A#eqw~;Smm#2@a2N;74$H+Vv%oHhoiZ{K_K3@OwHq zyt6m}DL6cGg+;Ei$Wn{sE%J~>p0&tsi+sf*KeEV4i=2*M>cQc)Vzfo3TV$a{@)p@> zk?j`wl11LM$d4>?!XiWPOFcNeR*bhui$!j;NQXrpu*epRylj!zEOO8yKedSbUl+d_ zUMt4pw|j7SWST|hSmaKNlr8d@MLuJZ*DUfai@a@-lNK3`U+Tf(wPLbGW?E#aMR>m< zIJ|N;TI6|)@P0#ZcxQdvBF8N9JBy6L@ABaA%9&!3*%n!Bk(Czdx5$$g*=>=pTjYBd zdB-9H@tZq1yjGlRk;^Qy&?5I(g!dAH!z=kAi#%W%G6uiP zgTp)P5{t~W$ekAHwa7+`?6AlliyW}X+ZOq)MMmIPcyM^FxY#0Ti`-z5yDZXUkq0gE zfQSUB1Qbl-c?W4>)<^k$%oh}w)))uS~{ zZ9Pg;QJB%0iYkoC459v^7oSTMrZ2PC&hs%VK=myv*o(GQfD&b?P~EqzDm^X=dm=_(XD1xX+10m*sqaiICMnM`XCH79$s8Np! zulu2WW<)vqG>C2tv)Z@}KLFz!pl8De%7+n~_{7@W4Q;#Mzm_!kVEQlVoNDy>l zE6j=+Uxl$x(7s8bswFDW1Xfcd3NW-%J`JNlKkCmSb~DuPzyw1Fw@t-%75p#Fm`(S- z=AxDoej!GwN*&q-ho6J7OTp+3J`!UUX4b@y&I|4I@5ET#K0l1YQ;qA?s=6O_7aIFt zbm1?tSdg0%O&gSJ-#6`pG2sPJay>3Ag4UzwY@I}k+1QVkvlV8S`O$Hqp$Du6NimSdBhYaOBE>i^2Pf|8J9G8VoUsGE=x8U8a!8#Q_)E z8?`tPg}pfNv9>s1rbUe@7d79~{6^EhDiheM+>7Fh(%>~*Z@lthnb1`EvWy8O`pbY4 w^%bxn+RMlz$}1#(be9hrMRi51Bi0W}0m`V-sJ5V2G}@SxXf6M$^{>qQAGn5Z>i_@% literal 0 HcmV?d00001 diff --git a/src/gpgme.lib b/src/gpgme.lib new file mode 100644 index 0000000000000000000000000000000000000000..23f4e7014e99abbe2a450f994d159f6521dbade9 GIT binary patch literal 38658 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 literal 0 HcmV?d00001 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" {