RetroShare/libretroshare/src/pqi/authgpg.cc
thunder2 acf57ed3fd Removed read/write mutex from AuthGPGimpl and from the sources.
Added RsThread as base class to AuthGPGimpl and load all gpg keys every hour.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3571 b45a01b8-16f6-495d-af2f-9b41ad6348cc
2010-09-30 19:05:43 +00:00

2317 lines
64 KiB
C++

/*
* libretroshare/src AuthGPG.cc
*
* GnuPG/GPGme interface for RetroShare.
*
* Copyright 2008-2009 by Robert Fernie, Retroshare Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the termsf the GNU Library General Public
* License Version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*
*/
#include "authgpg.h"
#include "retroshare/rsiface.h"
#include "retroshare/rsinit.h"
#include <util/rsdir.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include "serialiser/rsconfigitems.h"
#include "cleanupxpgp.h"
const time_t STORE_KEY_TIMEOUT = 1 * 60 * 60; //store key is call around every hour
//#define GPG_DEBUG 1
static AuthGPGimpl *instance_gpg = NULL;
void AuthGPGInit()
{
instance_gpg = new AuthGPGimpl();
}
void AuthGPGExit()
{
if (instance_gpg) {
instance_gpg->join();
delete(instance_gpg);
instance_gpg = NULL;
}
}
AuthGPG *AuthGPG::getAuthGPG()
{
return instance_gpg;
}
/* Turn a set of parameters into a string */
#if 0
static std::string setKeyPairParams(bool useRsa, unsigned int blen,
std::string name, std::string comment, std::string email);
#endif
static std::string setKeyPairParams(bool useRsa, unsigned int blen,
std::string name, std::string comment, std::string email,
std::string inPassphrase);
#ifdef UNUSED_CODE
static gpgme_key_t getKey(gpgme_ctx_t, std::string, std::string, std::string);
#endif
static gpg_error_t keySignCallback(void *, gpgme_status_code_t, \
const char *, int);
static gpg_error_t trustCallback(void *, gpgme_status_code_t, \
const char *, int);
static void ProcessPGPmeError(gpgme_error_t ERR);
/* Function to sign X509_REQ via GPGme.
*/
gpgcert::gpgcert()
:key(NULL)
{
return;
}
gpgcert::~gpgcert()
{
if (key)
{
gpgme_key_unref(key);
}
}
#define GPG_DEBUG2
gpg_error_t pgp_pwd_callback(void *hook, const char *uid_hint, const char *passphrase_info, int prev_was_bad, int fd)
{
#ifdef GPG_DEBUG2
fprintf(stderr, "pgp_pwd_callback() called.\n");
#endif
std::string text = rsicontrol->getNotify().askForPassword(uid_hint,prev_was_bad);
#ifdef GPG_DEBUG2
std::cerr << "pgp_pwd_callback() got GPG passwd from gui." << std::endl;
#endif
if((void*)fd != NULL)
{
#ifndef WINDOWS_SYS
write(fd, text.c_str(), text.size());
write(fd, "\n", 1); /* needs a new line? */
#else
DWORD written = 0;
HANDLE winFd = (HANDLE) fd;
WriteFile(winFd, text.c_str(), text.size(), &written, NULL);
WriteFile(winFd, "\n", 1, &written, NULL);
#endif
}
#ifdef GPG_DEBUG2
fprintf(stderr, "pgp_pwd_callback() password setted\n");
#endif
return 0;
}
AuthGPGimpl::AuthGPGimpl()
:p3Config(CONFIG_TYPE_AUTHGPG),gpgmeInit(false),gpgmeKeySelected(false)
{
{
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
#ifdef LC_MESSAGES
gpgme_set_locale(NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
#endif
#ifndef WINDOWS_SYS
/* setup the engine (gpg2) */
// if (GPG_ERR_NO_ERROR != gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, "/usr/bin/gpg2", NULL))
// {
// std::cerr << "Error creating Setting engine" << std::endl;
// return;
// }
#endif
if (GPG_ERR_NO_ERROR != gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP))
{
std::cerr << "Error check engine version" << std::endl;
return;
}
if (GPG_ERR_NO_ERROR != gpgme_get_engine_info(&INFO))
{
std::cerr << "Error getting engine info" << std::endl;
while (INFO && INFO->protocol != GPGME_PROTOCOL_OpenPGP) {
INFO = INFO->next;
}
if (!INFO) {
fprintf (stderr, "GPGME compiled without support for protocol %s",
gpgme_get_protocol_name (INFO->protocol));
} else if (INFO->file_name && !INFO->version) {
fprintf (stderr, "Engine %s not installed properly",
INFO->file_name);
} else if (INFO->file_name && INFO->version && INFO->req_version) {
fprintf (stderr, "Engine %s version %s installed, "
"but at least version %s required", INFO->file_name,
INFO->version, INFO->req_version);
} else {
fprintf (stderr, "Unknown problem with engine for protocol %s",
gpgme_get_protocol_name (INFO->protocol));
}
return;
}
/* Create New Contexts */
if (GPG_ERR_NO_ERROR != gpgme_new(&CTX))
{
std::cerr << "Error creating GPGME Context" << std::endl;
return;
}
gpgme_set_passphrase_cb(CTX, pgp_pwd_callback, (void *) NULL);
}
}
/* Initialize */
bool AuthGPGimpl::InitAuth ()
{
std::string HomeDir;
#ifdef WINDOWS_SYS
if (RsInit::isPortable ()) {
// set home dir of gpg to configdir\gnupg
HomeDir = RsInit::RsConfigDirectory() + RsInit::dirSeperator() + "gnupg";
if (!RsDirUtil::checkCreateDirectory(HomeDir)) {
std::cerr << "Error creating gnupg directory" << std::endl;
return false;
}
}
#endif
/* setup protocol and homedir */
if (GPG_ERR_NO_ERROR != gpgme_ctx_set_engine_info(CTX, GPGME_PROTOCOL_OpenPGP, NULL, HomeDir.empty () ? NULL : HomeDir.c_str ()))
{
std::cerr << "Error creating Setting Protocol" << std::endl;
return false;
}
gpgmeInit = true;
storeAllKeys();
#ifdef GPG_DEBUG
printAllKeys_locked();
#endif
//updateTrustAllKeys_locked();
/* start thread */
start();
return true;
}
/* This function is called when retroshare is first started
* to get the list of available GPG certificates.
* This function should only return certs for which
* the private(secret) keys are available.
*
* returns false if GnuPG is not available.
*/
bool AuthGPGimpl::availableGPGCertificatesWithPrivateKeys(std::list<std::string> &ids)
{
int i = 0;
gpgme_key_t KEY = NULL;
gpg_error_t ERR;
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
if (!gpgmeInit)
{
return false;
}
} /******* UNLOCKED ******/
/* XXX should check that CTX is valid */
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
/* Initiates a key listing */
if (GPG_ERR_NO_ERROR != gpgme_op_keylist_start (CTX, "", 1))
{
std::cerr << "Error iterating through KeyList" << std::endl;
return false;
}
/* Loop until end of key */
for(i = 0;(GPG_ERR_NO_ERROR == (ERR = gpgme_op_keylist_next (CTX, &KEY))); i++)
{
if (KEY->subkeys)
{
ids.push_back(KEY->subkeys->keyid);
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::availablePGPCertificates() Added: " << KEY->subkeys->keyid << std::endl;
#endif
}
else
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::availablePGPCertificates() Missing subkey" << std::endl;
#endif
}
}
if (GPG_ERR_NO_ERROR != gpgme_op_keylist_end(CTX))
{
std::cerr << "Error ending KeyList" << std::endl;
return false;
}
std::cerr << "AuthGPGimpl::availablePGPCertificates() Secret Key Count: " << i << std::endl;
/* return false if there are no private keys */
return (i > 0);
}
/* You can initialise Retroshare with
* (a) load existing certificate.
* (b) a new certificate.
*
* This function must be called successfully (return == 1)
* before anything else can be done. (except above fn).
*/
int AuthGPGimpl::GPGInit(std::string ownId)
{
std::cerr << "AuthGPGimpl::GPGInit() called with own gpg id : " << ownId << std::endl;
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
if (!gpgmeInit) {
return 0;
}
mOwnGpgId = ownId;
}
storeAllKeys();
int lvl = 0;
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
if (mOwnGpgCert.id != mOwnGpgId) {
std::cerr << "AuthGPGimpl::GPGInit() failed to find your id." << std::endl;
return 0;
}
gpgmeKeySelected = true;
lvl = mOwnGpgCert.validLvl;
}
//force the validity of the private key. When set to unknown, it caused signature and text encryptions bugs
privateTrustCertificate(mOwnGpgId, 5);
//printAllKeys_locked();
std::cerr << "AuthGPGimpl::GPGInit finished." << std::endl;
return 1;
}
AuthGPGimpl::~AuthGPGimpl()
{
}
void AuthGPGimpl::run()
{
int count = 0;
while (m_bRun)
{
#ifdef WIN32
Sleep(1000);
#else
sleep(1);
#endif
/* every minute */
if (++count >= 60) {
storeAllKeys_tick();
count = 0;
}
}
}
bool AuthGPGimpl::storeAllKeys_tick() {
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::storeAllKeys_tick() called." << std::endl;
#endif
time_t timeSinceStore = 0;
{
RsStackMutex stack(gpgMtxData);
timeSinceStore = time(NULL) - mStoreKeyTime;
}
if (timeSinceStore > STORE_KEY_TIMEOUT)
{
storeAllKeys();
}
return true ;
}
// store all keys in map mKeyList to avoid callin gpgme exe repeatedly
bool AuthGPGimpl::storeAllKeys()
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::storeAllKeys()" << std::endl;
#endif
std::string ownGpgId;
/* store member variables locally */
{
RsStackMutex stack(gpgMtxData);
if (!gpgmeInit)
{
std::cerr << "AuthGPGimpl::storeAllKeys() Error since GPG is not initialised" << std::endl;
return false;
}
mStoreKeyTime = time(NULL);
ownGpgId = mOwnGpgId;
}
/* read keys from gpg to local list */
std::list<gpgcert> keyList;
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::storeAllKeys() clearing existing ones" << std::endl;
#endif
gpg_error_t ERR;
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
/* enable SIG mode */
gpgme_keylist_mode_t origmode = gpgme_get_keylist_mode(CTX);
gpgme_keylist_mode_t mode = origmode | GPGME_KEYLIST_MODE_SIGS;
gpgme_set_keylist_mode(CTX, mode);
/* store keys */
gpgme_key_t KEY = NULL;
/* Initiates a key listing 0 = All Keys */
if (GPG_ERR_NO_ERROR != gpgme_op_keylist_start (CTX, "", 0))
{
std::cerr << "AuthGPGimpl::storeAllKeys() Error iterating through KeyList" << std::endl;
// if (rsicontrol != NULL) {
// rsicontrol->getNotify().notifyErrorMsg(0,0,"Error reading gpg keyring, cannot acess key list.");
// }
gpgme_set_keylist_mode(CTX, origmode);
return false;
}
/* Loop until end of key */
ERR = gpgme_op_keylist_next (CTX, &KEY);
if (GPG_ERR_NO_ERROR != ERR) {
std::cerr << "AuthGPGimpl::storeAllKeys() didn't find any gpg key in the keyring" << std::endl;
// if (rsicontrol != NULL) {
// rsicontrol->getNotify().notifyErrorMsg(0,0,"Error reading gpg keyring, cannot find any key in the list.");
// }
gpgme_set_keylist_mode(CTX, origmode);
return false;
}
for(int i = 0;GPG_ERR_NO_ERROR == ERR; i++)
{
/* store in pqiAuthDetails */
gpgcert nu;
/* NB subkeys is a linked list and can contain multiple keys.
* first key is primary.
*/
if ((!KEY->subkeys) || (!KEY->uids))
{
std::cerr << "AuthGPGimpl::storeAllKeys() Invalid Key in List... skipping" << std::endl;
continue;
}
/* In general MainSubKey is used to sign all others!
* Don't really need to worry about other ids either.
*/
gpgme_subkey_t mainsubkey = KEY->subkeys;
nu.id = mainsubkey->keyid;
nu.fpr = mainsubkey->fpr;
#ifdef GPG_DEBUG
std::cerr << "MAIN KEYID: " << nu.id << " FPR: " << nu.fpr << std::endl;
gpgme_subkey_t subkeylist = KEY->subkeys;
while(subkeylist != NULL)
{
std::cerr << "\tKEYID: " << subkeylist->keyid << " FPR: " << subkeylist->fpr << std::endl;
subkeylist = subkeylist->next;
}
#endif
/* NB uids is a linked list and can contain multiple ids.
* first id is primary.
*/
gpgme_user_id_t mainuid = KEY->uids;
nu.name = mainuid->name;
nu.email = mainuid->email;
gpgme_key_sig_t mainsiglist = mainuid->signatures;
nu.ownsign = false;
while(mainsiglist != NULL)
{
if (mainsiglist->status == GPG_ERR_NO_ERROR)
{
/* add as a signature ... even if the
* we haven't go the peer yet.
* (might be yet to come).
*/
std::string keyid = mainsiglist->keyid;
if (nu.signers.end() == std::find(
nu.signers.begin(),
nu.signers.end(),keyid))
{
nu.signers.push_back(keyid);
}
if (keyid == ownGpgId) {
nu.ownsign = true;
}
}
mainsiglist = mainsiglist->next;
}
#ifdef GPG_DEBUG
gpgme_user_id_t uidlist = KEY->uids;
while(uidlist != NULL)
{
std::cerr << "\tUID: " << uidlist->uid;
std::cerr << " NAME: " << uidlist->name;
std::cerr << " EMAIL: " << uidlist->email;
std::cerr << " VALIDITY: " << uidlist->validity;
std::cerr << std::endl;
gpgme_key_sig_t usiglist = uidlist->signatures;
while(usiglist != NULL)
{
std::cerr << "\t\tSIG KEYID: " << usiglist->keyid;
std::cerr << " UID: " << usiglist->uid;
std::cerr << " NAME: " << usiglist->name;
std::cerr << " EMAIL: " << usiglist->email;
std::cerr << " VALIDITY: " << (usiglist->status == GPG_ERR_NO_ERROR);
std::cerr << std::endl;
usiglist = usiglist->next;
}
uidlist = uidlist->next;
}
#endif
/* signatures are attached to uids... but only supplied
* if GPGME_KEYLIST_MODE_SIGS is on.
* signature notation supplied is GPGME_KEYLIST_MODE_SIG_NOTATION is on
*/
nu.trustLvl = KEY->owner_trust;
nu.validLvl = mainuid->validity;
/* grab a reference, so the key remains */
gpgme_key_ref(KEY);
nu.key = KEY;
/* store in map */
keyList.push_back(nu);
#ifdef GPG_DEBUG
std::cerr << "nu.name" << nu.name << std::endl;
std::cerr << "nu.trustLvl" << nu.trustLvl << std::endl;
std::cerr << "nu.accept_connection" << nu.accept_connection << std::endl;
#endif
ERR = gpgme_op_keylist_next (CTX, &KEY);
}
if (GPG_ERR_NO_ERROR != gpgme_op_keylist_end(CTX))
{
std::cerr << "Error ending KeyList" << std::endl;
gpgme_set_keylist_mode(CTX, origmode);
return false;
}
gpgme_set_keylist_mode(CTX, origmode);
}
/* process read gpg keys and store it in member */
std::list<std::string> gpg_change_trust_list;
{
RsStackMutex stack(gpgMtxData);
//let's start a new list
mKeyList.clear();
for (std::list<gpgcert>::iterator it = keyList.begin(); it != keyList.end(); it++) {
gpgcert &nu = *it;
std::map<std::string, bool>::iterator itAccept;
if (mAcceptToConnectMap.end() != (itAccept = mAcceptToConnectMap.find(nu.id))) {
nu.accept_connection = itAccept->second;
} else {
nu.accept_connection = false;
mAcceptToConnectMap[nu.id] = false;
}
if (nu.trustLvl < 2 && nu.accept_connection) {
//add it to the list of key that we will force the trust to 2
gpg_change_trust_list.push_back(nu.id);
}
/* grab a reference, so the key remains */
gpgme_key_ref(nu.key);
mKeyList[nu.id] = nu;
//store own key
if (nu.id == mOwnGpgId) {
/* grab a reference, so the key remains */
gpgme_key_ref(nu.key);
gpgme_key_unref(mOwnGpgCert.key);
mOwnGpgCert = nu;
}
}
}
std::list<std::string>::iterator it;
for(it = gpg_change_trust_list.begin(); it != gpg_change_trust_list.end(); it++)
{
privateTrustCertificate(*it, 3);
}
return true;
}
// update trust on all available keys. Not used anymore
//bool AuthGPGimpl::updateTrustAllKeys_locked()
//{
// gpg_error_t ERR;
// if (!gpgmeInit)
// {
// std::cerr << "Error since GPG is not initialised" << std::endl;
// return false;
// }
//
//
// /* have to do this the hard way! */
// std::map<std::string, gpgcert>::iterator it;
//
// for(it = mKeyList.begin(); it != mKeyList.end(); it++)
// {
// /* check for trust items associated with key */
// std::string peerid = it->second.email;
//#ifdef GPG_DEBUG
// std::cerr << "Searching GPGme for TrustInfo on: " << peerid << std::endl;
//#endif
//
// /* Initiates a key listing. NB: maxlevel is ignored!*/
// if (GPG_ERR_NO_ERROR != (ERR = gpgme_op_trustlist_start (CTX, peerid.c_str(), 0)))
// {
// std::cerr << "Error Starting Trust List" << std::endl;
// ProcessPGPmeError(ERR);
// continue;
// }
//
//
// /* Loop until end of key */
//#ifdef GPG_DEBUG
// gpgme_trust_item_t ti = NULL;
//
// for(int i = 0;(GPG_ERR_NO_ERROR == (ERR = gpgme_op_trustlist_next (CTX, &ti))); i++)
// {
// std::string keyid = ti->keyid;
// int type = ti->type;
// int level = ti->level;
//
// /* identify the peers, and add trust level */
// std::cerr << "GPGme Trust Item for: " << keyid;
// std::cerr << std::endl;
//
// std::cerr << "\t Type: " << type;
// std::cerr << " Level: " << level;
// std::cerr << std::endl;
//
// std::cerr << "\t Owner Trust: " << ti->owner_trust;
// std::cerr << " Validity: " << ti->validity;
// std::cerr << " Name: " << ti->name;
// std::cerr << std::endl;
// }
// std::cerr << "End of TrustList Iteration." << std::endl;
//#endif
// ProcessPGPmeError(ERR);
//
// if (GPG_ERR_NO_ERROR != gpgme_op_trustlist_end(CTX))
// {
// std::cerr << "Error ending TrustList" << std::endl;
//
// ProcessPGPmeError(ERR);
// }
// }
//
// return true;
//
//}
bool AuthGPGimpl::printAllKeys_locked()
{
certmap::const_iterator it;
for(it = mKeyList.begin(); it != mKeyList.end(); it++)
{
std::cerr << "PGP Key: " << it->second.id << std::endl;
std::cerr << "\tName: " << it->second.name << std::endl;
std::cerr << "\tEmail: " << it->second.email << std::endl;
std::cerr << "\townsign: " << it->second.ownsign << std::endl;
std::cerr << "\ttrustLvl: " << it->second.trustLvl << std::endl;
std::cerr << "\tvalidLvl: " << it->second.validLvl << std::endl;
std::cerr << "\tEmail: " << it->second.email << std::endl;
std::list<std::string>::const_iterator sit;
for(sit = it->second.signers.begin();
sit != it->second.signers.end(); sit++)
{
std::cerr << "\t\tSigner ID:" << *sit;
/* do a naughty second search.. should be ok
* as we aren't modifying list.
*/
certmap::const_iterator kit = mKeyList.find(*sit);
if (kit != mKeyList.end())
{
std::cerr << " Name:" << kit->second.name << std::endl;
}
}
}
return true;
}
bool AuthGPGimpl::printOwnKeys_locked()
{
certmap::iterator it;
for(it = mKeyList.begin(); it != mKeyList.end(); it++)
{
if (it->second.ownsign)
{
std::cerr << "Own PGP Key: " << it->second.id << std::endl;
std::cerr << "\tName: " << it->second.name << std::endl;
std::cerr << "\tEmail: " << it->second.email << std::endl;
}
}
return true;
}
bool AuthGPGimpl::printKeys()
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
printAllKeys_locked();
return printOwnKeys_locked();
}
void ProcessPGPmeError(gpgme_error_t ERR)
{
gpgme_err_code_t code = gpgme_err_code(ERR);
gpgme_err_source_t src = gpgme_err_source(ERR);
if(code > 0)
{
std::cerr << "GPGme ERROR: Code: " << code << " Source: " << src << std::endl;
std::cerr << "GPGme ERROR: " << gpgme_strerror(ERR) << std::endl;
}
}
void print_pgpme_verify_summary(unsigned int summary)
{
std::cerr << "\tFLAGS:";
if (summary & GPGME_SIGSUM_VALID)
std::cerr << " VALID ";
if (summary & GPGME_SIGSUM_GREEN)
std::cerr << " GREEN ";
if (summary & GPGME_SIGSUM_RED)
std::cerr << " RED ";
if (summary & GPGME_SIGSUM_KEY_REVOKED)
std::cerr << " KEY_REVOKED ";
if (summary & GPGME_SIGSUM_KEY_EXPIRED)
std::cerr << " KEY_EXPIRED ";
if (summary & GPGME_SIGSUM_SIG_EXPIRED)
std::cerr << " SIG_EXPIRED ";
if (summary & GPGME_SIGSUM_KEY_MISSING)
std::cerr << " KEY_MISSING ";
if (summary & GPGME_SIGSUM_CRL_MISSING)
std::cerr << " CRL_MISSING ";
if (summary & GPGME_SIGSUM_CRL_TOO_OLD)
std::cerr << " CRL_TOO_OLD ";
if (summary & GPGME_SIGSUM_BAD_POLICY)
std::cerr << " BAD_POLICY ";
if (summary & GPGME_SIGSUM_SYS_ERROR)
std::cerr << " SYS_ERROR ";
std::cerr << std::endl;
}
bool AuthGPGimpl::DoOwnSignature(const void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl)
{
gpgcert ownGpgCert;
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
/* grab a reference, so the key remains */
gpgme_key_ref(mOwnGpgCert.key);
ownGpgCert = mOwnGpgCert;
} /******* UNLOCKED ******/
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
/* setup signers */
gpgme_signers_clear(CTX);
if (GPG_ERR_NO_ERROR != gpgme_signers_add(CTX, ownGpgCert.key))
{
std::cerr << "AuthGPGimpl::DoOwnSignature() Error Adding Signer" << std::endl;
}
gpgme_data_t gpgmeData;
gpgme_data_t gpgmeSig;
if (GPG_ERR_NO_ERROR != gpgme_data_new_from_mem(&gpgmeData, (const char *) data, datalen, 1))
{
std::cerr << "Error create Data" << std::endl;
}
if (GPG_ERR_NO_ERROR != gpgme_data_new(&gpgmeSig))
{
std::cerr << "Error create Sig" << std::endl;
}
/* move string data to gpgmeData */
gpgme_set_armor (CTX, 0);
gpgme_sig_mode_t mode = GPGME_SIG_MODE_DETACH;
gpg_error_t ERR;
if (GPG_ERR_NO_ERROR != (ERR = gpgme_op_sign(CTX,gpgmeData, gpgmeSig, mode)))
{
ProcessPGPmeError(ERR);
std::cerr << "AuthGPGimpl::Sign FAILED ERR: " << ERR << std::endl;
gpgme_data_release(gpgmeSig);
gpgme_data_release(gpgmeData);
gpgme_signers_clear(CTX);
return false;
}
gpgme_sign_result_t res = gpgme_op_sign_result(CTX);
if (res)
{
#ifdef GPG_DEBUG
fprintf(stderr, "Sign Got Result\n");
#endif
}
else
{
fprintf(stderr, "Sign Failed to get Result\n");
}
#ifdef GPG_DEBUG
gpgme_invalid_key_t ik = res->invalid_signers;
gpgme_new_signature_t sg = res->signatures;
while(ik != NULL)
{
fprintf(stderr, "AuthGPGimpl::Sign, Invalid by: %s\n", ik->fpr);
ik = ik->next;
}
while(sg != NULL)
{
fprintf(stderr, "AuthGPGimpl::Signed by: %s\n", sg->fpr);
sg = sg->next;
}
#endif
/* now extract the data from gpgmeSig */
size_t len = 0;
// gpgme_data_write (gpgmeSig, "", 1); // to be able to convert it into a string
char *export_sig = gpgme_data_release_and_get_mem(gpgmeSig, &len);
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::Signature len: " << len << std::endl;
#endif
if (len < *outl) // -1 because we added a 0 at the end.
{
std::cerr << "Length is smaller. Reducing to " << len << std::endl;
*outl = len;
}
memmove(buf_sigout, export_sig, *outl);
gpgme_free(export_sig);
gpgme_data_release (gpgmeData);
gpgme_signers_clear(CTX);
/* extract id(s)! */
return true;
}
/* import to GnuPG and other Certificates */
bool AuthGPGimpl::VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, std::string withfingerprint)
{
gpgme_data_t gpgmeSig;
gpgme_data_t gpgmeData;
#ifdef GPG_DEBUG
std::cerr << "VerifySignature: datalen: " << datalen << " siglen: " << siglen << std::endl;
#endif
if (!active())
{
return false ;
}
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
// if(siglen==73)
// {
// //std::cerr << "Reducing to 72 to overcome an old bug." << std::endl ;
// siglen=72 ;
// }
if (GPG_ERR_NO_ERROR != gpgme_data_new_from_mem(&gpgmeData, (const char *) data, datalen, 1))
{
std::cerr << "Error create Data" << std::endl;
}
if (siglen != 0 && GPG_ERR_NO_ERROR != gpgme_data_new_from_mem(&gpgmeSig, (const char *) sig, siglen, 1))
{
std::cerr << "Error create Sig" << std::endl;
}
/* move string data to gpgmeData */
gpgme_set_armor (CTX, 0);
gpgme_error_t ERR;
if (GPG_ERR_NO_ERROR != (ERR = gpgme_op_verify(CTX,gpgmeSig, gpgmeData, NULL)))
{
ProcessPGPmeError(ERR);
std::cerr << "AuthGPGimpl::Verify FAILED" << std::endl;
}
gpgme_verify_result_t res = gpgme_op_verify_result(CTX);
if (res)
{
#ifdef GPG_DEBUG
fprintf(stderr, "VerifySignature Got Result\n");
#endif
}
else
{
#ifdef GPG_DEBUG
fprintf(stderr, "VerifySignature Failed to get Result\n");
#endif
gpgme_data_release(gpgmeData);
gpgme_data_release(gpgmeSig);
return false ;
}
gpgme_signature_t sg = res->signatures;
bool valid = false;
while(sg != NULL)
{
#ifdef GPG_DEBUG
fprintf(stderr, "AuthGPGimpl::Verify Sig by: %s, status: %d\n", sg->fpr, sg->status);
print_pgpme_verify_summary(sg->summary);
#endif
if (sg->status == GPG_ERR_NO_ERROR)
{
#ifdef GPG_DEBUG
fprintf(stderr, "AuthGPGimpl::VerifySignature() OK\n");
#endif
if (withfingerprint.empty() == false && withfingerprint == sg->fpr) {
#ifdef GPG_DEBUG
fprintf(stderr, "AuthGPGimpl::VerifySignature() for the fingerprint key : ");
std::cerr << withfingerprint;
fprintf(stderr, "\n");
#endif
valid = true;
break;
}
}
sg = sg->next;
}
gpgme_data_release (gpgmeData);
gpgme_data_release (gpgmeSig);
/* extract id(s)! */
if (!valid)
{
fprintf(stderr, "AuthGPGimpl::VerifySignature() FAILED\n");
}
return valid;
}
bool AuthGPGimpl::active()
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
return ((gpgmeInit) && (gpgmeKeySelected));
}
bool AuthGPGimpl::GeneratePGPCertificate(std::string name, std::string email, std::string passwd, std::string &pgpId, std::string &errString) {
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
gpgme_key_t newKey;
gpgme_genkey_result_t result;
gpg_error_t ERR;
if(GPG_ERR_NO_ERROR != (ERR = gpgme_op_genkey(CTX, setKeyPairParams(true, 2048, name, "generated by Retroshare", email, \
passwd).c_str(), NULL, NULL))) {
ProcessPGPmeError(ERR);
std::cerr << "Error generating the key" << std::endl;
return 0;
}
if((result = gpgme_op_genkey_result(CTX)) == NULL)
return 0;
if(GPG_ERR_NO_ERROR != (ERR = gpgme_get_key(CTX, result->fpr, &newKey, 1))) {
std::cerr << "Error reading own key" << std::endl;
return 0;
}
pgpId = newKey->subkeys->keyid;
return true;
}
bool AuthGPGimpl::CloseAuth()
{
return true;
}
/**** These Two are common */
std::string AuthGPGimpl::getGPGName(GPG_id id)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(id)))
return it->second.name;
return std::string();
}
/**** These Two are common */
std::string AuthGPGimpl::getGPGEmail(GPG_id id)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(id)))
return it->second.email;
return std::string();
}
/**** GPG versions ***/
std::string AuthGPGimpl::getGPGOwnId()
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
return mOwnGpgId;
}
std::string AuthGPGimpl::getGPGOwnName()
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
return mOwnGpgCert.name;
}
bool AuthGPGimpl::getGPGAllList(std::list<std::string> &ids)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
/* add an id for each pgp certificate */
certmap::iterator it;
for(it = mKeyList.begin(); it != mKeyList.end(); it++)
{
ids.push_back(it->first);
}
return true;
}
bool AuthGPGimpl::getGPGDetails(std::string id, RsPeerDetails &d)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::getPGPDetails() called for : " << id << std::endl;
#endif
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
/* add an id for each pgp certificate */
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(id)))
{
gpgcert &cert = it->second;
d.id = cert.id; //keep, it but can be bug gen
d.gpg_id = cert.id;
d.name = cert.name;
d.email = cert.email;
d.trustLvl = cert.trustLvl;
d.validLvl = cert.validLvl;
d.ownsign = cert.ownsign;
d.gpgSigners = cert.signers;
d.fpr = cert.fpr;
d.accept_connection = cert.accept_connection;
//did the peer signed me ?
d.hasSignedMe = false;
std::list<std::string>::iterator signersIt;
for(signersIt = mOwnGpgCert.signers.begin(); signersIt != mOwnGpgCert.signers.end() ; ++signersIt)
if (*signersIt == d.id)
{
d.hasSignedMe = true;
break;
}
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::getPGPDetails() Name : " << cert.name << std::endl;
#endif
return true;
}
return false;
}
bool AuthGPGimpl::decryptText(gpgme_data_t CIPHER, gpgme_data_t PLAIN) {
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
gpgme_set_armor (CTX, 1);
gpg_error_t ERR;
if (GPG_ERR_NO_ERROR != (ERR = gpgme_op_decrypt (CTX, CIPHER, PLAIN)))
{
ProcessPGPmeError(ERR);
std::cerr << "AuthGPGimpl::decryptText() Error decrypting text." << std::endl;
return false;
}
return true;
}
bool AuthGPGimpl::encryptText(gpgme_data_t PLAIN, gpgme_data_t CIPHER) {
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
gpgme_encrypt_flags_t* flags = new gpgme_encrypt_flags_t();
gpgme_key_t keys[2] = {mOwnGpgCert.key, NULL};
gpgme_set_armor (CTX, 1);
gpg_error_t ERR;
if (GPG_ERR_NO_ERROR != (ERR = gpgme_op_encrypt(CTX, keys, *flags, PLAIN, CIPHER)))
{
ProcessPGPmeError(ERR);
std::cerr << "AuthGPGimpl::encryptText() Error encrypting text." << std::endl;
return false;
}
return true;
}
bool AuthGPGimpl::getGPGValidList(std::list<std::string> &ids)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
/* add an id for each pgp certificate */
certmap::iterator it;
for(it = mKeyList.begin(); it != mKeyList.end(); it++)
{
if (it->second.validLvl >= GPGME_VALIDITY_MARGINAL) {
ids.push_back(it->first);
}
}
return true;
}
bool AuthGPGimpl::getGPGAcceptedList(std::list<std::string> &ids)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
for(it = mKeyList.begin(); it != mKeyList.end(); it++)
{
if (it->second.accept_connection)
{
ids.push_back(it->first);
}
}
return true;
}
bool AuthGPGimpl::getGPGSignedList(std::list<std::string> &ids)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
for(it = mKeyList.begin(); it != mKeyList.end(); it++)
{
if (it->second.ownsign)
{
ids.push_back(it->first);
}
}
return true;
}
bool AuthGPGimpl::isGPGValid(GPG_id id)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(id))) {
return (it->second.validLvl >= GPGME_VALIDITY_MARGINAL);
} else {
return false;
}
}
bool AuthGPGimpl::isGPGId(GPG_id id)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(id))) {
return true;
} else {
return false;
}
}
bool AuthGPGimpl::isGPGSigned(GPG_id id)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(id)))
{
return (it->second.ownsign);
}
return false;
}
bool AuthGPGimpl::isGPGAccepted(GPG_id id)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(id)))
{
return (it->second.accept_connection);
}
return false;
}
/*****************************************************************
* Loading and Saving Certificates - this has to
* be able to handle both openpgp and X509 certificates.
*
* X509 are passed onto AuthSSL, OpenPGP are passed to gpgme.
*
*/
/* SKTAN : do not know how to use std::string id */
std::string AuthGPGimpl::SaveCertificateToString(std::string id)
{
if (!isGPGId(id)) {
std::cerr << "AuthGPGimpl::SaveCertificateToString() unknown ID" << std::endl;
return "";
}
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
std::string tmp;
const char *pattern[] = { NULL, NULL };
pattern[0] = id.c_str();
gpgme_data_t gpgmeData;
if (GPG_ERR_NO_ERROR != gpgme_data_new (&gpgmeData))
{
std::cerr << "Error create Data" << std::endl;
}
gpgme_set_armor (CTX, 1);
if (GPG_ERR_NO_ERROR != gpgme_op_export_ext (CTX, pattern, 0, gpgmeData))
{
std::cerr << "Error export Data" << std::endl;
}
fflush (NULL);
//showData (gpgmeData);
size_t len = 0;
char *export_txt = gpgme_data_release_and_get_mem(gpgmeData, &len);
char *str = new char[len+1] ;
memcpy(str,export_txt,len) ;
str[len]=0 ;
tmp = std::string(str);
delete[] str ;
#ifdef GPG_DEBUG
std::cerr << "Exported Certificate: " << std::endl << tmp << std::endl;
#endif
gpgme_free(export_txt);
return tmp;
}
/* import to GnuPG and other Certificates */
bool AuthGPGimpl::LoadCertificateFromString(std::string str, std::string &gpg_id)
{
if (str == "") {
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::LoadCertificateFromString() cert is empty string, returning false." << std::endl;
#endif
return false;
}
int imported = 0;
std::string fingerprint;
{
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
//std::string cleancert = cleanUpCertificate(str); disable for p3disc message on windows system. Move the clean cert in p3peers
std::string cleancert = str;
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::LoadCertificateFromString() cleancert : " << cleancert;
#endif
gpgme_data_t gpgmeData;
if (GPG_ERR_NO_ERROR != gpgme_data_new_from_mem(&gpgmeData, cleancert.c_str(), cleancert.length(), 1))
{
std::cerr << "Error create Data" << std::endl;
return false;
}
/* move string data to gpgmeData */
gpgme_set_armor (CTX, 1);
if (GPG_ERR_NO_ERROR != gpgme_op_import (CTX,gpgmeData))
{
std::cerr << "AuthGPGimpl::LoadCertificateFromString() Error Importing Certificate" << std::endl;
gpgme_data_release (gpgmeData);
return false ;
}
gpgme_import_result_t res = gpgme_op_import_result(CTX);
if(res == NULL || res->imports == NULL) {
gpgme_data_release (gpgmeData);
return false ;
}
fingerprint = std::string(res->imports->fpr);
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::LoadCertificateFromString() Importing considered folowing fpr : " << fingerprint << std::endl;
#endif
imported = res->imported;
#ifdef GPG_DEBUG
fprintf(stderr, "ImportCertificate(Considered: %d Imported: %d)\n",
res->considered, res->imported);
#endif
/* do we need to delete res??? */
gpgme_data_release (gpgmeData);
}
/* extract id(s)! (only if we actually imported one) */
if (imported) {
storeAllKeys();
}
//retrieve the id of the key
certmap::iterator it;
gpg_id = "" ;
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
for(it = mKeyList.begin(); it != mKeyList.end(); it++)
{
if (it->second.fpr == fingerprint)
{
gpg_id = it->second.id;
break;
}
}
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::LoadCertificateFromString() returning with gpg_id : " << gpg_id << std::endl;
#endif
if (gpg_id == "") {
return false;
} else {
return true;
}
}
/*****************************************************************
* Auth...? Signing, Revoke, Trust are all done at
* the PGP level....
*
* Only Signing of SSL is done at setup.
* Auth should be done... ?? not sure
* maybe
*
*/
/*************************************/
/* These take PGP Ids */
bool AuthGPGimpl::setAcceptToConnectGPGCertificate(std::string gpg_id, bool acceptance)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::markGPGCertificateAsFriends(" << gpg_id << ")" << std::endl;
#endif
/* reload stuff now ... */
storeAllKeys();
{
RsStackMutex stack(gpgMtxData);
certmap::iterator it;
if (mKeyList.end() == (it = mKeyList.find(gpg_id))) {
return false;
}
it->second.accept_connection = acceptance;
mAcceptToConnectMap[gpg_id] = acceptance;
}
storeAllKeys();
IndicateConfigChanged();
return true;
}
/* These take PGP Ids */
bool AuthGPGimpl::SignCertificateLevel0(GPG_id id)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::SignCertificat(" << id << ")" << std::endl;
#endif
if (1 != privateSignCertificate(id))
{
storeAllKeys();
return false;
}
/* reload stuff now ... */
storeAllKeys();
return true;
}
bool AuthGPGimpl::RevokeCertificate(std::string id)
{
//RsStackMutex stack(gpgMtx); /******* LOCKED ******/
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::RevokeCertificate(" << id << ") not implemented yet" << std::endl;
#endif
return false;
}
bool AuthGPGimpl::TrustCertificate(std::string id, int trustlvl)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::TrustCertificate(" << id << ", " << trustlvl << ")" << std::endl;
#endif
if (1 != privateTrustCertificate(id, trustlvl))
{
storeAllKeys();
return false;
}
/* Keys are reloaded by privateTrustCertificate */
return true;
}
#if 0
/* remove otherwise will cause bugs */
bool AuthGPGimpl::SignData(std::string input, std::string &sign)
{
return false;
}
bool AuthGPGimpl::SignData(const void *data, const uint32_t len, std::string &sign)
{
return false;
}
bool AuthGPGimpl::SignDataBin(std::string input, unsigned char *sign, unsigned int *signlen)
{
return false;
}
#endif
bool AuthGPGimpl::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen) {
return DoOwnSignature(data, datalen,
sign, signlen);
}
bool AuthGPGimpl::VerifySignBin(const void *data, uint32_t datalen, unsigned char *sign, unsigned int signlen, std::string withfingerprint) {
return VerifySignature(data, datalen,
sign, signlen, withfingerprint);
}
/* Sign/Trust stuff */
int AuthGPGimpl::privateSignCertificate(std::string id)
{
/* The key should be in Others list and not in Peers list ??
* Once the key is signed, it moves from Others to Peers list ???
*/
gpgcert signKey;
gpgcert ownKey;
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
certmap::iterator it;
if (mKeyList.end() == (it = mKeyList.find(id)))
{
return false;
}
/* grab a reference, so the key remains */
gpgme_key_ref(it->second.key);
signKey = it->second;
/* grab a reference, so the key remains */
gpgme_key_ref(mOwnGpgCert.key);
ownKey = mOwnGpgCert;
} /******* UNLOCKED ******/
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
class SignParams sparams("0");
class EditParams params(SIGN_START, &sparams);
gpgme_data_t out;
gpg_error_t ERR;
if(GPG_ERR_NO_ERROR != (ERR = gpgme_data_new(&out))) {
return 0;
}
gpgme_signers_clear(CTX);
if(GPG_ERR_NO_ERROR != (ERR = gpgme_signers_add(CTX, ownKey.key))) {
gpgme_data_release(out);
return 0;
}
if(GPG_ERR_NO_ERROR != (ERR = gpgme_op_edit(CTX, signKey.key, keySignCallback, &params, out))) {
gpgme_data_release(out);
gpgme_signers_clear(CTX);
return 0;
}
gpgme_data_release(out);
gpgme_signers_clear(CTX);
return 1;
}
/* revoke the signature on Certificate */
int AuthGPGimpl::privateRevokeCertificate(std::string id)
{
//RsStackMutex stack(gpgMtx); /******* LOCKED ******/
return 0;
}
int AuthGPGimpl::privateTrustCertificate(std::string id, int trustlvl)
{
/* The certificate should be in Peers list ??? */
if(!isGPGAccepted(id)) {
std::cerr << "Invalid Certificate" << std::endl;
return 0;
}
{
gpgcert trustCert;
{
RsStackMutex stack(gpgMtxData);
trustCert = mKeyList.find(id)->second;
} /******* UNLOCKED ******/
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
gpgme_key_t trustKey = trustCert.key;
std::string trustString;
std::ostringstream trustStrOut;
trustStrOut << trustlvl;
class TrustParams sparams(trustStrOut.str());
class EditParams params(TRUST_START, &sparams);
gpgme_data_t out;
gpg_error_t ERR;
if(GPG_ERR_NO_ERROR != (ERR = gpgme_data_new(&out))) {
return 0;
}
if(GPG_ERR_NO_ERROR != (ERR = gpgme_op_edit(CTX, trustKey, trustCallback, &params, out))) {
gpgme_data_release(out);
return 0;
}
gpgme_data_release(out);
//the key ref has changed, we got to get rid of the old reference.
trustCert.key = NULL;
}
storeAllKeys();
return 1;
}
/* This function to print Data */
#if 0
void showData(gpgme_data_t dh)
{
#define BUF_SIZE 512
char buf[BUF_SIZE + 1];
int ret;
ret = gpgme_data_seek (dh, 0, SEEK_SET);
if (ret)
{
std::cerr << "Fail data seek" << std::endl;
// fail_if_err (gpgme_err_code_from_errno (errno));
}
while ((ret = gpgme_data_read (dh, buf, BUF_SIZE)) > 0)
fwrite (buf, ret, 1, stdout);
if (ret < 0)
{
std::cerr << "Fail data seek" << std::endl;
//fail_if_err (gpgme_err_code_from_errno (errno));
}
}
#endif
#if 0
static std::string setKeyPairParams(bool useRsa, unsigned int blen,
std::string name, std::string comment, std::string email)
{
std::ostringstream params;
params << "<GnupgKeyParms format=\"internal\">"<< std::endl;
if (useRsa)
{
params << "Key-Type: RSA"<< std::endl;
if (blen < 1024)
{
#ifdef GPG_DEBUG
std::cerr << "Weak Key... strengthing..."<< std::endl;
#endif
blen = 1024;
}
blen = ((blen / 512) * 512); /* make multiple of 512 */
params << "Key-Length: "<< blen << std::endl;
}
else
{
params << "Key-Type: DSA"<< std::endl;
params << "Key-Length: 1024"<< std::endl;
params << "Subkey-Type: ELG-E"<< std::endl;
params << "Subkey-Length: 1024"<< std::endl;
}
params << "Name-Real: "<< name << std::endl;
params << "Name-Comment: "<< comment << std::endl;
params << "Name-Email: "<< email << std::endl;
params << "Expire-Date: 0"<< std::endl;
params << "</GnupgKeyParms>"<< std::endl;
return params.str();
}
#endif
static std::string setKeyPairParams(bool useRsa, unsigned int blen,
std::string name, std::string comment, std::string email,
std::string inPassphrase)
{
std::ostringstream params;
params << "<GnupgKeyParms format=\"internal\">"<< std::endl;
if (useRsa)
{
params << "Key-Type: RSA"<< std::endl;
if (blen < 1024)
{
#ifdef GPG_DEBUG
std::cerr << "Weak Key... strengthing..."<< std::endl;
#endif
blen = 1024;
}
blen = ((blen / 512) * 512); /* make multiple of 512 */
params << "Key-Length: "<< blen << std::endl;
}
else
{
params << "Key-Type: DSA"<< std::endl;
params << "Key-Length: 1024"<< std::endl;
params << "Subkey-Type: ELG-E"<< std::endl;
params << "Subkey-Length: 1024"<< std::endl;
}
params << "Name-Real: "<< name << std::endl;
params << "Name-Comment: "<< comment << std::endl;
params << "Name-Email: "<< email << std::endl;
params << "Expire-Date: 0"<< std::endl;
params << "Passphrase: "<< inPassphrase << std::endl;
params << "</GnupgKeyParms>"<< std::endl;
return params.str();
}
/* Author: Shiva
* This function returns the key macthing the user parameters
* from the keyring
*/
#ifdef UNUSED_CODE
static gpgme_key_t getKey(gpgme_ctx_t CTX, std::string name, std::string comment, std::string email) {
gpgme_key_t key;
gpgme_user_id_t user;
/* Initiates a key listing */
if (GPG_ERR_NO_ERROR != gpgme_op_keylist_start (CTX, "", 0))
{
std::cerr << "Error iterating through KeyList";
std::cerr << std::endl;
return false;
}
/* Loop until end of key */
for(int i = 0;(GPG_ERR_NO_ERROR == gpgme_op_keylist_next (CTX, &key)); i++)
{
user = key->uids;
while(user != NULL) {
if((name.size() && name == user->name) && (comment.size() && comment == user->comment) && \
(email.size() && email == user->email))
{
/* grab a reference to the key */
gpgme_op_keylist_end(CTX);
if (GPG_ERR_NO_ERROR != gpgme_op_keylist_end(CTX))
{
std::cerr << "Error ending KeyList";
std::cerr << std::endl;
}
gpgme_key_ref(key);
return key;
}
user = user->next;
}
}
if (GPG_ERR_NO_ERROR != gpgme_op_keylist_end(CTX))
{
std::cerr << "Error ending KeyList" << std::endl;
}
return NULL;
}
#endif
/* Callback function for key signing */
static gpg_error_t keySignCallback(void *opaque, gpgme_status_code_t status, \
const char *args, int fd) {
class EditParams *params = (class EditParams *)opaque;
class SignParams *sparams = (class SignParams *)params->oParams;
const char *result = NULL;
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback status: %d args: %s, params->state: %d\n", status, args, params->state);
/* printf stuff out */
if (status == GPGME_STATUS_EOF)
fprintf(stderr,"keySignCallback GPGME_STATUS_EOF\n");
if (status == GPGME_STATUS_GOT_IT)
fprintf(stderr,"keySignCallback GPGME_STATUS_GOT_IT\n");
if (status == GPGME_STATUS_USERID_HINT)
fprintf(stderr,"keySignCallback GPGME_STATUS_USERID_HINT\n");
if (status == GPGME_STATUS_NEED_PASSPHRASE)
fprintf(stderr,"keySignCallback GPGME_STATUS_NEED_PASSPHRASE\n");
if (status == GPGME_STATUS_GOOD_PASSPHRASE)
fprintf(stderr,"keySignCallback GPGME_STATUS_GOOD_PASSPHRASE\n");
if (status == GPGME_STATUS_BAD_PASSPHRASE)
fprintf(stderr,"keySignCallback GPGME_STATUS_BAD_PASSPHRASE\n");
if (status == GPGME_STATUS_GET_LINE)
fprintf(stderr,"keySignCallback GPGME_STATUS_GET_LINE\n");
if (status == GPGME_STATUS_GET_BOOL)
fprintf(stderr,"keySignCallback GPGME_STATUS_GET_BOOL\n");
if (status == GPGME_STATUS_ALREADY_SIGNED)
fprintf(stderr,"keySignCallback GPGME_STATUS_ALREADY_SIGNED\n");
/* printf stuff out */
if (params->state == SIGN_START)
fprintf(stderr,"keySignCallback params->state SIGN_START\n");
if (params->state == SIGN_COMMAND)
fprintf(stderr,"keySignCallback params->state SIGN_COMMAND\n");
if (params->state == SIGN_UIDS)
fprintf(stderr,"keySignCallback params->state SIGN_UIDS\n");
if (params->state == SIGN_SET_EXPIRE)
fprintf(stderr,"keySignCallback params->state SIGN_SET_EXPIRE\n");
if (params->state == SIGN_SET_CHECK_LEVEL)
fprintf(stderr,"keySignCallback params->state SIGN_SET_CHECK_LEVEL\n");
if (params->state == SIGN_CONFIRM)
fprintf(stderr,"keySignCallback params->state SIGN_CONFIRM\n");
if (params->state == SIGN_QUIT)
fprintf(stderr,"keySignCallback params->state SIGN_QUIT\n");
if (params->state == SIGN_ENTER_PASSPHRASE)
fprintf(stderr,"keySignCallback params->state SIGN_ENTER_PASSPHRASE\n");
if (params->state == SIGN_ERROR)
fprintf(stderr,"keySignCallback params->state SIGN_ERROR");
#endif
if(status == GPGME_STATUS_EOF ||
status == GPGME_STATUS_GOT_IT ||
status == GPGME_STATUS_USERID_HINT ||
status == GPGME_STATUS_NEED_PASSPHRASE ||
// status == GPGME_STATUS_GOOD_PASSPHRASE ||
status == GPGME_STATUS_BAD_PASSPHRASE) {
fprintf(stderr,"keySignCallback Error status\n");
ProcessPGPmeError(params->err);
return params->err;
}
switch (params->state)
{
case SIGN_START:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_START\n");
#endif
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args)))
{
params->state = SIGN_COMMAND;
result = "sign";
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_COMMAND:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_COMMAND\n");
#endif
if (status == GPGME_STATUS_GET_BOOL &&
(!std::string("keyedit.sign_all.okay").compare(args)))
{
params->state = SIGN_UIDS;
result = "Y";
}
else if (status == GPGME_STATUS_GET_BOOL &&
(!std::string("sign_uid.okay").compare(args)))
{
params->state = SIGN_ENTER_PASSPHRASE;
result = "Y";
}
else if (status == GPGME_STATUS_GET_LINE &&
(!std::string("sign_uid.expire").compare(args)))
{
params->state = SIGN_SET_EXPIRE;
result = "Y";
}
else if (status == GPGME_STATUS_GET_LINE &&
(!std::string("sign_uid.class").compare(args)))
{
params->state = SIGN_SET_CHECK_LEVEL;
result = sparams->checkLvl.c_str();
}
else if (status == GPGME_STATUS_ALREADY_SIGNED)
{
/* The key has already been signed with this key */
params->state = SIGN_QUIT;
result = "quit";
}
else if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args)))
{
/* Failed sign: expired key */
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_UIDS:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_UIDS\n");
#endif
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("sign_uid.expire").compare(args)))
{
params->state = SIGN_SET_EXPIRE;
result = "Y";
}
else if (status == GPGME_STATUS_GET_LINE &&
(!std::string("sign_uid.class").compare(args)))
{
params->state = SIGN_SET_CHECK_LEVEL;
result = sparams->checkLvl.c_str();
}
else if (status == GPGME_STATUS_GET_BOOL &&
(!std::string("sign_uid.okay").compare(args)))
{
params->state = SIGN_ENTER_PASSPHRASE;
result = "Y";
}
else if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args)))
{
/* Failed sign: expired key */
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_SET_EXPIRE:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_SET_EXPIRE\n");
#endif
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("sign_uid.class").compare(args)))
{
params->state = SIGN_SET_CHECK_LEVEL;
result = sparams->checkLvl.c_str();
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_SET_CHECK_LEVEL:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_SET_CHECK_LEVEL\n");
#endif
if (status == GPGME_STATUS_GET_BOOL &&
(!std::string("sign_uid.okay").compare(args)))
{
params->state = SIGN_ENTER_PASSPHRASE;
result = "Y";
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_ENTER_PASSPHRASE:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_ENTER_PASSPHRASE\n");
#endif
if (status == GPGME_STATUS_GOOD_PASSPHRASE)
{
params->state = SIGN_CONFIRM;
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_CONFIRM:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_CONFIRM\n");
#endif
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args)))
{
params->state = SIGN_QUIT;
result = "quit";
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_QUIT:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_QUIT\n");
#endif
if (status == GPGME_STATUS_GET_BOOL &&
(!std::string("keyedit.save.okay").compare(args)))
{
params->state = SIGN_SAVE;
result = "Y";
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case SIGN_ERROR:
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback SIGN_ERROR\n");
#endif
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args)))
{
/* Go to quit operation state */
params->state = SIGN_QUIT;
result = "quit";
}
else
{
params->state = SIGN_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
default:
fprintf(stderr,"keySignCallback UNKNOWN state\n");
break;
}
if (result)
{
#ifdef GPG_DEBUG
fprintf(stderr,"keySignCallback result:%s\n", result);
#endif
#ifndef WINDOWS_SYS
if (*result)
{
write (fd, result, strlen (result));
write (fd, "\n", 1);
}
#else
DWORD written = 0;
HANDLE winFd = (HANDLE) fd;
if (*result)
{
WriteFile(winFd, result, strlen(result), &written, NULL);
WriteFile(winFd, "\n", 1, &written, NULL);
}
#endif
}
fprintf(stderr,"keySignCallback Error status\n");
ProcessPGPmeError(params->err);
return params->err;
}
/* Callback function for assigning trust level */
static gpgme_error_t trustCallback(void *opaque, gpgme_status_code_t status, \
const char *args, int fd) {
class EditParams *params = (class EditParams *)opaque;
class TrustParams *tparams = (class TrustParams *)params->oParams;
const char *result = NULL;
/* printf stuff out */
#ifdef GPG_DEBUG
if (status == GPGME_STATUS_EOF)
fprintf(stderr,"keySignCallback GPGME_STATUS_EOF\n");
if (status == GPGME_STATUS_GOT_IT)
fprintf(stderr,"keySignCallback GPGME_STATUS_GOT_IT\n");
if (status == GPGME_STATUS_USERID_HINT)
fprintf(stderr,"keySignCallback GPGME_STATUS_USERID_HINT\n");
if (status == GPGME_STATUS_NEED_PASSPHRASE)
fprintf(stderr,"keySignCallback GPGME_STATUS_NEED_PASSPHRASE\n");
if (status == GPGME_STATUS_GOOD_PASSPHRASE)
fprintf(stderr,"keySignCallback GPGME_STATUS_GOOD_PASSPHRASE\n");
if (status == GPGME_STATUS_BAD_PASSPHRASE)
fprintf(stderr,"keySignCallback GPGME_STATUS_BAD_PASSPHRASE\n");
if (status == GPGME_STATUS_GET_LINE)
fprintf(stderr,"keySignCallback GPGME_STATUS_GET_LINE\n");
if (status == GPGME_STATUS_GET_BOOL)
fprintf(stderr,"keySignCallback GPGME_STATUS_GET_BOOL \n");
if (status == GPGME_STATUS_ALREADY_SIGNED)
fprintf(stderr,"keySignCallback GPGME_STATUS_ALREADY_SIGNED\n");
/* printf stuff out */
if (params->state == TRUST_START)
fprintf(stderr,"keySignCallback params->state TRUST_START\n");
if (params->state == TRUST_COMMAND)
fprintf(stderr,"keySignCallback params->state TRUST_COMMAND\n");
if (params->state == TRUST_VALUE)
fprintf(stderr,"keySignCallback params->state TRUST_VALUE\n");
if (params->state == TRUST_REALLY_ULTIMATE)
fprintf(stderr,"keySignCallback params->state TRUST_REALLY_ULTIMATE\n");
if (params->state == TRUST_QUIT)
fprintf(stderr,"keySignCallback params->state TRUST_QUIT\n");
if (params->state == TRUST_ERROR)
fprintf(stderr,"keySignCallback params->state TRUST_ERROR\n");
#endif
if(status == GPGME_STATUS_EOF ||
status == GPGME_STATUS_GOT_IT) {
return params->err;
}
switch (params->state)
{
case TRUST_START:
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args))) {
params->state = TRUST_COMMAND;
result = "trust";
} else {
params->state = TRUST_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_COMMAND:
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("edit_ownertrust.value").compare(args))) {
params->state = TRUST_VALUE;
result = tparams->trustLvl.c_str();;
} else {
params->state = TRUST_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_VALUE:
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args))) {
params->state = TRUST_QUIT;
result = "quit";
}
else if (status == GPGME_STATUS_GET_BOOL &&
(!std::string("edit_ownertrust.set_ultimate.okay").compare(args))) {
params->state = TRUST_REALLY_ULTIMATE;
result = "Y";
}
else {
params->state = TRUST_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_REALLY_ULTIMATE:
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args))) {
params->state = TRUST_QUIT;
result = "quit";
} else {
params->state = TRUST_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_QUIT:
if (status == GPGME_STATUS_GET_BOOL &&
(!std::string("keyedit.save.okay").compare(args))) {
params->state = TRUST_SAVE;
result = "Y";
} else {
params->state = TRUST_ERROR;
params->err = gpg_error (GPG_ERR_GENERAL);
}
break;
case TRUST_ERROR:
if (status == GPGME_STATUS_GET_LINE &&
(!std::string("keyedit.prompt").compare(args))) {
/* Go to quit operation state */
params->state = TRUST_QUIT;
result = "quit";
} else {
params->state = TRUST_ERROR;
}
break;
}
if (result)
{
#ifndef WINDOWS_SYS
if (*result)
write (fd, result, strlen (result));
write (fd, "\n", 1);
#else
DWORD written = 0;
HANDLE winFd = (HANDLE) fd;
if (*result)
WriteFile(winFd, result, strlen (result), &written, NULL);
WriteFile(winFd, "\n", 1, &written, NULL);
#endif
#ifdef GPG_DEBUG
std::cerr << "trustCallback() result : " << result << std::endl;
#endif
}
return params->err;
}
// -----------------------------------------------------------------------------------//
// -------------------------------- Config functions ------------------------------ //
// -----------------------------------------------------------------------------------//
//
RsSerialiser *AuthGPGimpl::setupSerialiser()
{
RsSerialiser *rss = new RsSerialiser ;
rss->addSerialType(new RsGeneralConfigSerialiser());
return rss ;
}
std::list<RsItem*> AuthGPGimpl::saveList(bool& cleanup)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::saveList() called" << std::endl ;
#endif
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
cleanup = true ;
std::list<RsItem*> lst ;
// Now save config for network digging strategies
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ;
std::map<std::string, bool>::iterator mapIt;
for (mapIt = mAcceptToConnectMap.begin(); mapIt != mAcceptToConnectMap.end(); mapIt++) {
if (mapIt->first == mOwnGpgId) {
continue;
}
RsTlvKeyValue kv;
kv.key = mapIt->first;
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::saveList() called (mapIt->second) : " << (mapIt->second) << std::endl ;
#endif
kv.value = (mapIt->second)?"TRUE":"FALSE" ;
vitem->tlvkvs.pairs.push_back(kv) ;
}
lst.push_back(vitem);
return lst ;
}
bool AuthGPGimpl::loadList(std::list<RsItem*> load)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::loadList() Item Count: " << load.size() << std::endl;
#endif
storeAllKeys();
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
/* load the list of accepted gpg keys */
std::list<RsItem *>::iterator it;
for(it = load.begin(); it != load.end(); it++) {
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet *>(*it);
if(vitem) {
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::loadList() General Variable Config Item:" << std::endl;
vitem->print(std::cerr, 10);
std::cerr << std::endl;
#endif
std::list<RsTlvKeyValue>::iterator kit;
for(kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); kit++) {
if (kit->key == mOwnGpgId) {
continue;
}
mAcceptToConnectMap[kit->key] = (kit->value == "TRUE");
//set the gpg key
certmap::iterator it;
if (mKeyList.end() != (it = mKeyList.find(kit->key))) {
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::loadList() setting accept to : " << (kit->value == "TRUE");
std::cerr << " for gpg key id : " << kit->key << std::endl;
#endif
it->second.accept_connection = (kit->value == "TRUE");
}
}
}
delete (*it);
}
return true;
}