From edd13ba38aad31d7627a74da67f51ed2daf21b67 Mon Sep 17 00:00:00 2001 From: drbob Date: Sat, 23 May 2009 17:40:35 +0000 Subject: [PATCH] Missed these files from libretroshare git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1267 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/pqi/authgpg.cc | 2174 +++++++++++++++++++++++++++++ libretroshare/src/pqi/authgpg.h | 378 +++++ libretroshare/src/pqi/gpgme_tst.c | 76 + 3 files changed, 2628 insertions(+) create mode 100644 libretroshare/src/pqi/authgpg.cc create mode 100644 libretroshare/src/pqi/authgpg.h create mode 100644 libretroshare/src/pqi/gpgme_tst.c diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc new file mode 100644 index 000000000..88ff65bb1 --- /dev/null +++ b/libretroshare/src/pqi/authgpg.cc @@ -0,0 +1,2174 @@ +/* + * libretroshare/src gpgauthmgr.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". + * + * + */ + +/**** + * At an SSL Certificate level: + * Processx509() calls (virtual) ValidateCertificate() to check if it correctly + * signed by an known PGP certificate. + * + * this will return true - even if the pgp cert is not authed. + * + * a connection will cause VerifyX509Callback to be called. This is a virtual fn. + * + * AuthCertificate() is called to make a certificate authenticated. + * this does nothing but set a flag at the SSL level + * no real auth at SSL only level. + * + * GPG Functions: + * ValidateCertificate() calls, + * bool GPGAuthMgr::AuthX509(X509 *x509) + * VerifySignature() + * + * VerifyX509Callback() + * calls AuthX509(). + * calls isPGPAuthenticated(std::string id) + * + * AuthCertificate(). + * check isPGPAuthenticated(). + * if not - sign PGP certificate. + */ + +#include "authgpg.h" +#include +#include + +/* Turn a set of parameters into a string */ +static std::string setKeyPairParams(bool useRsa, unsigned int blen, + std::string name, std::string comment, std::string email, + std::string passphrase); + +static gpgme_key_t getKey(gpgme_ctx_t, std::string, std::string, std::string); + +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. + */ + +// the single instance of this, but only when SSL Only +static GPGAuthMgr instance_gpgroot; + +p3AuthMgr *getAuthMgr() +{ + return &instance_gpgroot; +} + + +gpg_error_t pgp_pwd_callback(void *hook, const char *uid_hint, const char *passphrase_info, int prev_was_bad, int fd) +{ + const char *passwd = (const char *) hook; + write(fd, passwd, strlen(passwd)); + + return 0; +} + + +GPGAuthMgr::GPGAuthMgr() + :gpgmeInit(false) +{ + + setlocale(LC_ALL, ""); + gpgme_check_version(NULL); + gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL)); + + #ifndef HAVE_W32_SYSTEM + gpgme_set_locale(NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL)); + #endif + + if (GPG_ERR_NO_ERROR != gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP)) + { + std::cerr << "Error check engine version"; + std::cerr << std::endl; + return; + } + + if (GPG_ERR_NO_ERROR != gpgme_get_engine_info(&INFO)) + { + std::cerr << "Error getting engine info"; + std::cerr << std::endl; + return; + } + + /* Create New Contexts */ + if (GPG_ERR_NO_ERROR != gpgme_new(&CTX)) + { + std::cerr << "Error creating GPGME Context"; + std::cerr << std::endl; + return; + } + + /* setup the protocol */ + if (GPG_ERR_NO_ERROR != gpgme_set_protocol(CTX, GPGME_PROTOCOL_OpenPGP)) + { + std::cerr << "Error creating Setting Protocol"; + std::cerr << std::endl; + return; + } + + /* if we get to here -> we have inited okay */ + gpgmeInit = true; + + storeAllKeys(); + printAllKeys(); + updateTrustAllKeys(); + +static const char *realPassword = "aaaa\n"; + gpgme_set_passphrase_cb(CTX, pgp_pwd_callback, (void *) realPassword); + +} + +/* 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 GPGAuthMgr::availablePGPCertificates(std::list &ids) +{ + int i = 0; + gpgme_key_t KEY = NULL; + gpg_error_t ERR; + + /* XXX should check that CTX is valid */ + if (!gpgmeInit) + { + return false; + } + + + /* Initiates a key listing */ + if (GPG_ERR_NO_ERROR != gpgme_op_keylist_start (CTX, "", 1)) + { + std::cerr << "Error iterating through KeyList"; + std::cerr << 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); + std::cerr << "GPGAuthMgr::availablePGPCertificates() Added: " + << KEY->subkeys->keyid << std::endl; + } + else + { + std::cerr << "GPGAuthMgr::availablePGPCertificates() Missing subkey" + << std::endl; + } + + /* release key */ + gpgme_key_release (KEY); + } + + if (GPG_ERR_NO_ERROR != gpgme_op_keylist_end(CTX)) + { + std::cerr << "Error ending KeyList"; + std::cerr << std::endl; + return false; + } + + std::cerr << "GPGAuthMgr::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 GPGAuthMgr::GPGInit(std::string ownId, std::string name, std::string passphrase) +{ + /* For now, I'll just load the key from the keyring and create the + * self certificate. Passphrase verification needs to be done + */ + gpgme_key_t newKey; + gpg_error_t ERR; + + if (!gpgmeInit) { + return 0; + } + +/***** + if (!isOwnCert(ownId)) + { + return 0; + } +*****/ + + if(GPG_ERR_NO_ERROR != (ERR = gpgme_get_key(CTX, ownId.c_str(), &newKey, 1))) { + std::cerr << "Error reading the key from keyring" << std::endl; + return 0; + } + + mOwnGpgCert.user.name = name; + mOwnGpgCert.user.email = newKey->uids->email; + mOwnGpgCert.user.fpr = newKey->subkeys->fpr; + mOwnGpgCert.user.id = ownId; + mOwnGpgCert.key = newKey; + this->passphrase = passphrase; + + mOwnId = ownId; + gpgmeKeySelected = true; + return true; +} + +int GPGAuthMgr::GPGInit(std::string name, std::string comment, + std::string email, std::string passphrase) +{ + gpgme_key_t newKey; + gpgme_genkey_result_t result; + gpg_error_t ERR; + + if (!gpgmeInit) { + return 0; + } + + if(GPG_ERR_NO_ERROR != (ERR = gpgme_op_genkey(CTX, setKeyPairParams(true, 2048, name, comment, email, \ + passphrase).c_str(), NULL, NULL))) { + 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; + } + + mOwnGpgCert.user.name = name; + mOwnGpgCert.user.email = email; + mOwnGpgCert.user.fpr = newKey->subkeys->fpr; + mOwnGpgCert.user.id = newKey->subkeys->keyid; + mOwnGpgCert.key = newKey; + this->passphrase = passphrase; + + mOwnId = mOwnGpgCert.user.id; + gpgmeKeySelected = true; + + return 1; +} + + GPGAuthMgr::~GPGAuthMgr() +{ +} + + +// store all keys in map mKeyList to avoid callin gpgme exe repeatedly +bool GPGAuthMgr::storeAllKeys() +{ + std::cerr << "GPGAuthMgr::storeAllKeys()"; + std::cerr << std::endl; + + gpg_error_t ERR; + if (!gpgmeInit) + { + std::cerr << "Error since GPG is not initialised"; + std::cerr << std::endl; + return false; + } + + /* 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 << "Error iterating through KeyList"; + std::cerr << std::endl; + gpgme_set_keylist_mode(CTX, origmode); + return false; + } + + /* Loop until end of key */ + for(int i = 0;(GPG_ERR_NO_ERROR == (ERR = gpgme_op_keylist_next (CTX, &KEY))); 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 << "Invalid Key in List... skipping"; + std::cerr << 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.user.id = mainsubkey->keyid; + nu.user.fpr = mainsubkey->fpr; + + std::cerr << "MAIN KEYID: " << nu.user.id; + std::cerr << " FPR: " << nu.user.fpr; + std::cerr << std::endl; + + + gpgme_subkey_t subkeylist = KEY->subkeys; + while(subkeylist != NULL) + { + std::cerr << "\tKEYID: " << subkeylist->keyid; + std::cerr << " FPR: " << subkeylist->fpr; + std::cerr << std::endl; + + subkeylist = subkeylist->next; + } + + + /* NB uids is a linked list and can contain multiple ids. + * first id is primary. + */ + + gpgme_user_id_t mainuid = KEY->uids; + nu.user.name = mainuid->name; + nu.user.email = mainuid->email; + gpgme_key_sig_t mainsiglist = mainuid->signatures; + 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.user.signers.end() == std::find( + nu.user.signers.begin(), + nu.user.signers.end(),keyid)) + { + nu.user.signers.push_back(keyid); + } + } + mainsiglist = mainsiglist->next; + } + + 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; + } + + /* 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.user.trustLvl = KEY->owner_trust; + nu.user.ownsign = KEY->can_sign; + nu.user.trusted = (mainuid->validity > GPGME_VALIDITY_MARGINAL); + + nu.key = KEY; + /* store in map */ + mKeyList[nu.user.id] = nu; + + /* release key */ + //gpgme_key_release (KEY); + } + + if (GPG_ERR_NO_ERROR != gpgme_op_keylist_end(CTX)) + { + std::cerr << "Error ending KeyList"; + std::cerr << std::endl; + gpgme_set_keylist_mode(CTX, origmode); + return false; + } + + gpgme_set_keylist_mode(CTX, origmode); + return true; + +} + +// update trust on all available keys. +bool GPGAuthMgr::updateTrustAllKeys() +{ + gpg_error_t ERR; + if (!gpgmeInit) + { + std::cerr << "Error since GPG is not initialised"; + std::cerr << std::endl; + return false; + } + + + /* have to do this the hard way! */ + gpgme_trust_item_t ti = NULL; + std::map::iterator it; + + for(it = mKeyList.begin(); it != mKeyList.end(); it++) + { + /* check for trust items associated with key */ + std::string peerid = it->second.user.email; + std::cerr << "Searching GPGme for TrustInfo on: " << peerid; + std::cerr << std::endl; + + /* 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::cerr << std::endl; + ProcessPGPmeError(ERR); + continue; + } + + + /* Loop until end of key */ + 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; + +#if 0 + if ( + + + /* store in pqiAuthDetails */ + gpgcert nu; + nu.user.id = (KEY->subkeys) ? KEY->subkeys->keyid : NULL; + nu.user.fpr= (KEY->subkeys) ? KEY->subkeys->fpr : NULL; + nu.user.name = (KEY->uids) ? KEY->uids->name : NULL; + nu.user.email = (KEY->uids) ? KEY->uids->email : NULL; + // nu.user.location = "here"; + // nu.user.org = "me.com"; + + nu.user.trustLvl = KEY->owner_trust; + nu.user.ownsign = KEY->can_sign; + nu.user.trusted = KEY->can_certify; + + nu.key = KEY; + /* store in map */ + mKeyList[nu.user.id] = nu; + + /* release key */ + //gpgme_key_release (KEY); +#endif + + } + + std::cerr << "End of TrustList Iteration."; + std::cerr << std::endl; + ProcessPGPmeError(ERR); + + if (GPG_ERR_NO_ERROR != gpgme_op_trustlist_end(CTX)) + { + std::cerr << "Error ending TrustList"; + std::cerr << std::endl; + + ProcessPGPmeError(ERR); + } + } + + return true; + +} +bool GPGAuthMgr::printAllKeys() +{ + certmap::const_iterator it; + for(it = mKeyList.begin(); it != mKeyList.end(); it++) + { + std::cerr << "PGP Key: " << it->second.user.id; + std::cerr << std::endl; + + std::cerr << "\tName: " << it->second.user.name; + std::cerr << std::endl; + std::cerr << "\tEmail: " << it->second.user.email; + std::cerr << std::endl; + + std::cerr << "\ttrustLvl: " << it->second.user.trustLvl; + std::cerr << std::endl; + std::cerr << "\townsign?: " << it->second.user.ownsign; + std::cerr << std::endl; + std::cerr << "\ttrusted?: " << it->second.user.trusted; + std::cerr << std::endl; + std::cerr << "\tEmail: " << it->second.user.email; + std::cerr << std::endl; + + std::list::const_iterator sit; + for(sit = it->second.user.signers.begin(); + sit != it->second.user.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.user.name; + std::cerr << std::endl; + } + } + } + return true; +} + +bool GPGAuthMgr::printOwnKeys() +{ + certmap::iterator it; + for(it = mKeyList.begin(); it != mKeyList.end(); it++) + { + if (it->second.user.ownsign) + { + std::cerr << "Own PGP Key: " << it->second.user.id; + std::cerr << std::endl; + + std::cerr << "\tName: " << it->second.user.name; + std::cerr << std::endl; + std::cerr << "\tEmail: " << it->second.user.email; + std::cerr << std::endl; + } + } + return true; +} + + +X509 *GPGAuthMgr::SignX509Req(X509_REQ *req, long days, std::string gpg_passwd) +{ + /* Transform the X509_REQ into a suitable format to + * generate DIGEST hash. (for SSL to do grunt work) + */ + + +#define SERIAL_RAND_BITS 64 + + const EVP_MD *digest = EVP_sha1(); + ASN1_INTEGER *serial = ASN1_INTEGER_new(); + EVP_PKEY *tmppkey; + X509 *x509 = X509_new(); + if (x509 == NULL) + { + std::cerr << "GPGAuthMgr::SignX509Req() FAIL" << std::endl; + return NULL; + } + + long version = 0x00; + unsigned long chtype = MBSTRING_ASC; + X509_NAME *issuer_name = X509_NAME_new(); + X509_NAME_add_entry_by_txt(issuer_name, "CN", chtype, + (unsigned char *) mOwnId.c_str(), -1, -1, 0); +/**** + X509_NAME_add_entry_by_NID(issuer_name, 48, 0, + (unsigned char *) "email@email.com", -1, -1, 0); + X509_NAME_add_entry_by_txt(issuer_name, "O", chtype, + (unsigned char *) "org", -1, -1, 0); + X509_NAME_add_entry_by_txt(x509_name, "L", chtype, + (unsigned char *) "loc", -1, -1, 0); +****/ + + std::cerr << "GPGAuthMgr::SignX509Req() Issuer name: " << mOwnId << std::endl; + + BIGNUM *btmp = BN_new(); + if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) + { + std::cerr << "GPGAuthMgr::SignX509Req() rand FAIL" << std::endl; + return NULL; + } + if (!BN_to_ASN1_INTEGER(btmp, serial)) + { + std::cerr << "GPGAuthMgr::SignX509Req() asn1 FAIL" << std::endl; + return NULL; + } + BN_free(btmp); + + if (!X509_set_serialNumber(x509, serial)) + { + std::cerr << "GPGAuthMgr::SignX509Req() serial FAIL" << std::endl; + return NULL; + } + ASN1_INTEGER_free(serial); + + /* Generate SUITABLE issuer name. + * Must reference OpenPGP key, that is used to verify it + */ + + if (!X509_set_issuer_name(x509, issuer_name)) + { + std::cerr << "GPGAuthMgr::SignX509Req() issue FAIL" << std::endl; + return NULL; + } + X509_NAME_free(issuer_name); + + + if (!X509_gmtime_adj(X509_get_notBefore(x509),0)) + { + std::cerr << "GPGAuthMgr::SignX509Req() notbefore FAIL" << std::endl; + return NULL; + } + + if (!X509_gmtime_adj(X509_get_notAfter(x509), (long)60*60*24*days)) + { + std::cerr << "GPGAuthMgr::SignX509Req() notafter FAIL" << std::endl; + return NULL; + } + + if (!X509_set_subject_name(x509, X509_REQ_get_subject_name(req))) + { + std::cerr << "GPGAuthMgr::SignX509Req() sub FAIL" << std::endl; + return NULL; + } + + tmppkey = X509_REQ_get_pubkey(req); + if (!tmppkey || !X509_set_pubkey(x509,tmppkey)) + { + std::cerr << "GPGAuthMgr::SignX509Req() pub FAIL" << std::endl; + return NULL; + } + + std::cerr << "X509 Cert, prepared for signing" << std::endl; + + /*** NOW The Manual signing bit (HACKED FROM asn1/a_sign.c) ***/ + int (*i2d)(X509_CINF*, unsigned char**) = i2d_X509_CINF; + X509_ALGOR *algor1 = x509->cert_info->signature; + X509_ALGOR *algor2 = x509->sig_alg; + ASN1_BIT_STRING *signature = x509->signature; + X509_CINF *data = x509->cert_info; + EVP_PKEY *pkey = NULL; + const EVP_MD *type = EVP_sha1(); + + EVP_MD_CTX ctx; + unsigned char *p,*buf_in=NULL; + unsigned char *buf_hashout=NULL,*buf_sigout=NULL; + int i,inl=0,hashoutl=0,hashoutll=0; + int sigoutl=0,sigoutll=0; + X509_ALGOR *a; + + EVP_MD_CTX_init(&ctx); + + /* FIX ALGORITHMS */ + + a = algor1; + ASN1_TYPE_free(a->parameter); + a->parameter=ASN1_TYPE_new(); + a->parameter->type=V_ASN1_NULL; + + ASN1_OBJECT_free(a->algorithm); + a->algorithm=OBJ_nid2obj(type->pkey_type); + + a = algor2; + ASN1_TYPE_free(a->parameter); + a->parameter=ASN1_TYPE_new(); + a->parameter->type=V_ASN1_NULL; + + ASN1_OBJECT_free(a->algorithm); + a->algorithm=OBJ_nid2obj(type->pkey_type); + + + std::cerr << "Algorithms Fixed" << std::endl; + + /* input buffer */ + inl=i2d(data,NULL); + buf_in=(unsigned char *)OPENSSL_malloc((unsigned int)inl); + + hashoutll=hashoutl=EVP_MD_size(type); + buf_hashout=(unsigned char *)OPENSSL_malloc((unsigned int)hashoutl); + + sigoutll=sigoutl=2048; // hashoutl; //EVP_PKEY_size(pkey); + buf_sigout=(unsigned char *)OPENSSL_malloc((unsigned int)sigoutl); + + std::cerr << "Buffer Sizes: in: " << inl; + std::cerr << " HashOut: " << hashoutl; + std::cerr << " SigOut: " << sigoutl; + std::cerr << std::endl; + + if ((buf_in == NULL) || (buf_hashout == NULL) || (buf_sigout == NULL)) + { + hashoutl=0; + sigoutl=0; + fprintf(stderr, "GPGAuthMgr::SignX509Req: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_MALLOC_FAILURE)\n"); + goto err; + } + p=buf_in; + + std::cerr << "Buffers Allocated" << std::endl; + + i2d(data,&p); + /* data in buf_in, ready to be hashed */ + EVP_DigestInit_ex(&ctx,type, NULL); + EVP_DigestUpdate(&ctx,(unsigned char *)buf_in,inl); + if (!EVP_DigestFinal(&ctx,(unsigned char *)buf_hashout, + (unsigned int *)&hashoutl)) + { + hashoutl=0; + fprintf(stderr, "GPGAuthMgr::SignX509Req: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_EVP_LIB)\n"); + goto err; + } + + std::cerr << "Digest Applied: len: " << hashoutl << std::endl; + + /* NOW Sign via GPG Functions */ + if (!DoOwnSignature(buf_hashout, hashoutl, buf_sigout, (unsigned int *) &sigoutl)) + { + sigoutl = 0; + goto err; + } + + passphrase = "NULL"; + + std::cerr << "Signature done: len:" << sigoutl << std::endl; + + /* ADD Signature back into Cert... Signed!. */ + + if (signature->data != NULL) OPENSSL_free(signature->data); + signature->data=buf_sigout; + buf_sigout=NULL; + signature->length=sigoutl; + /* In the interests of compatibility, I'll make sure that + * the bit string has a 'not-used bits' value of 0 + */ + signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + signature->flags|=ASN1_STRING_FLAG_BITS_LEFT; + + std::cerr << "Certificate Complete" << std::endl; + + return x509; + + + err: + /* cleanup */ + std::cerr << "GPGAuthMgr::SignX509Req() err: FAIL" << std::endl; + + return NULL; +} + + + +#if 0 + int ASN1_sign(int (*i2d)(), X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, char *data, EVP_PKEY *pkey, + const EVP_MD *type) + +#define X509_sign(x,pkey,md) \ + ASN1_sign((int (*)())i2d_X509_CINF, x->cert_info->signature, \ + x->sig_alg, x->signature, (char *)x->cert_info,pkey,md) + + + return NULL; +} +#endif + + +bool GPGAuthMgr::AuthX509(X509 *x509) +{ + /* extract CN for peer Id */ + X509_NAME *issuer = X509_get_issuer_name(x509); + std::string id = ""; + + /* verify signature */ + + /*** NOW The Manual signing bit (HACKED FROM asn1/a_sign.c) ***/ + int (*i2d)(X509_CINF*, unsigned char**) = i2d_X509_CINF; + ASN1_BIT_STRING *signature = x509->signature; + X509_CINF *data = x509->cert_info; + EVP_PKEY *pkey = NULL; + const EVP_MD *type = EVP_sha1(); + + EVP_MD_CTX ctx; + unsigned char *p,*buf_in=NULL; + unsigned char *buf_hashout=NULL,*buf_sigout=NULL; + int i,inl=0,hashoutl=0,hashoutll=0; + int sigoutl=0,sigoutll=0; + X509_ALGOR *a; + + fprintf(stderr, "GPGAuthMgr::AuthX509()\n"); + + EVP_MD_CTX_init(&ctx); + + /* input buffer */ + inl=i2d(data,NULL); + buf_in=(unsigned char *)OPENSSL_malloc((unsigned int)inl); + + hashoutll=hashoutl=EVP_MD_size(type); + buf_hashout=(unsigned char *)OPENSSL_malloc((unsigned int)hashoutl); + + sigoutll=sigoutl=2048; //hashoutl; //EVP_PKEY_size(pkey); + buf_sigout=(unsigned char *)OPENSSL_malloc((unsigned int)sigoutl); + + std::cerr << "Buffer Sizes: in: " << inl; + std::cerr << " HashOut: " << hashoutl; + std::cerr << " SigOut: " << sigoutl; + std::cerr << std::endl; + + if ((buf_in == NULL) || (buf_hashout == NULL) || (buf_sigout == NULL)) + { + hashoutl=0; + sigoutl=0; + fprintf(stderr, "GPGAuthMgr::AuthX509: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_MALLOC_FAILURE)\n"); + goto err; + } + p=buf_in; + + std::cerr << "Buffers Allocated" << std::endl; + + i2d(data,&p); + /* data in buf_in, ready to be hashed */ + EVP_DigestInit_ex(&ctx,type, NULL); + EVP_DigestUpdate(&ctx,(unsigned char *)buf_in,inl); + if (!EVP_DigestFinal(&ctx,(unsigned char *)buf_hashout, + (unsigned int *)&hashoutl)) + { + hashoutl=0; + fprintf(stderr, "GPGAuthMgr::AuthX509: ASN1err(ASN1_F_ASN1_SIGN,ERR_R_EVP_LIB)\n"); + goto err; + } + + std::cerr << "Digest Applied: len: " << hashoutl << std::endl; + + /* copy data into signature */ + sigoutl = signature->length; + memmove(buf_sigout, signature->data, sigoutl); + + /* NOW Sign via GPG Functions */ + if (!VerifySignature(id, buf_hashout, hashoutl, buf_sigout, (unsigned int) sigoutl)) + { + sigoutl = 0; + goto err; + } + + return true; + + err: + return false; +} + + +void ProcessPGPmeError(gpgme_error_t ERR) +{ + gpgme_err_code_t code = gpgme_err_code(ERR); + gpgme_err_source_t src = gpgme_err_source(ERR); + + 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_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 GPGAuthMgr::DoOwnSignature(void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl) +{ + /* setup signers */ + gpgme_signers_clear(CTX); + if (GPG_ERR_NO_ERROR != gpgme_signers_add(CTX, mOwnGpgCert.key)) + { + std::cerr << "GPGAuthMgr::DoOwnSignature() Error Adding Signer"; + std::cerr << 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::cerr << std::endl; + } + + if (GPG_ERR_NO_ERROR != gpgme_data_new(&gpgmeSig)) + { + std::cerr << "Error create Sig"; + std::cerr << 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 << "GPGAuthMgr::Sign FAILED ERR: " << ERR; + std::cerr << std::endl; + } + + gpgme_sign_result_t res = gpgme_op_sign_result(CTX); + + if (res) + { + fprintf(stderr, "Sign Got Result\n"); + } + else + { + fprintf(stderr, "Sign Failed to get Result\n"); + } + + gpgme_invalid_key_t ik = res->invalid_signers; + gpgme_new_signature_t sg = res->signatures; + while(ik != NULL) + { + fprintf(stderr, "GPGAuthMgr::Sign, Invalid by: %s\n", ik->fpr); + ik = ik->next; + } + + while(sg != NULL) + { + fprintf(stderr, "GPGAuthMgr::Signed by: %s\n", sg->fpr); + sg = sg->next; + } + + /* now extract the data from gpgmeSig */ + size_t len = 0; + char *export_sig = gpgme_data_release_and_get_mem(gpgmeSig, &len); + fprintf(stderr, "GPGAuthMgr::Signature len: %d \n", len); + if (len < *outl) + { + *outl = len; + } + memmove(buf_sigout, export_sig, *outl); + gpgme_free(export_sig); + gpgme_data_release (gpgmeData); + + /* extract id(s)! */ + return true; +} + + +/* import to GnuPG and other Certificates */ +bool GPGAuthMgr::VerifySignature(std::string id, void *data, int datalen, + void *sig, unsigned int siglen) +{ + gpgme_data_t gpgmeSig; + gpgme_data_t gpgmeData; + + std::cerr << "VerifySignature: datalen: " << datalen << " siglen: " << siglen; + std::cerr << std::endl; + + if (GPG_ERR_NO_ERROR != gpgme_data_new_from_mem(&gpgmeData, (const char *) data, datalen, 1)) + { + std::cerr << "Error create Data"; + std::cerr << std::endl; + } + + if (GPG_ERR_NO_ERROR != gpgme_data_new_from_mem(&gpgmeSig, (const char *) sig, siglen, 1)) + { + std::cerr << "Error create Sig"; + std::cerr << 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 << "GPGAuthMgr::Verify FAILED"; + std::cerr << std::endl; + } + + gpgme_verify_result_t res = gpgme_op_verify_result(CTX); + + if (res) + { + fprintf(stderr, "VerifySignature Got Result\n"); + } + else + { + fprintf(stderr, "VerifySignature Failed to get Result\n"); + } + + gpgme_signature_t sg = res->signatures; + bool valid = false; + + while(sg != NULL) + { + fprintf(stderr, "GPGAuthMgr::Verify Sig by: %s, Result: %d\n", sg->fpr, sg->summary); + print_pgpme_verify_summary(sg->summary); + + if (sg->summary & GPGME_SIGSUM_VALID) + { + fprintf(stderr, "GPGAuthMgr::VerifySignature() OK\n"); + valid = true; + } + + sg = sg->next; + } + + gpgme_data_release (gpgmeData); + gpgme_data_release (gpgmeSig); + + /* extract id(s)! */ + if (!valid) + { + fprintf(stderr, "GPGAuthMgr::VerifySignature() FAILED\n"); + } + + + return valid; +} + + + + +bool GPGAuthMgr::active() +{ + return ((gpgmeInit) && (gpgmeKeySelected) && (gpgmeX509Selected)); +} + +int GPGAuthMgr::InitAuth(const char *srvr_cert, const char *priv_key, + const char *passwd) +{ + /* Initialise the SSL part */ + if (AuthSSL::InitAuth(srvr_cert, priv_key, passwd)) + { + gpgmeX509Selected = true; + return 1; + } + + return 0; +} + +bool GPGAuthMgr::CloseAuth() +{ + return true; +} + +#if 0 /**** no saving here! let AuthSSL store directories! ****/ + +int GPGAuthMgr::setConfigDirectories(std::string confFile, std::string neighDir) +{ + return 1; +} + +#endif + +/**** The standard versions of the OwnId/get*List ... return SSL ids + * There are alternative functions for gpg ids. + ****/ + +std::string GPGAuthMgr::OwnId() +{ + /* to the external libretroshare world, we are our SSL id */ + return AuthSSL::OwnId(); +} + +bool GPGAuthMgr::getAllList(std::list &ids) +{ + /* get all of the certificates */ + return AuthSSL::getAllList(ids); +} + +bool GPGAuthMgr::getAuthenticatedList(std::list &ids) +{ + return AuthSSL::getAuthenticatedList(ids); +} + +bool GPGAuthMgr::getUnknownList(std::list &ids) +{ + return AuthSSL::getUnknownList(ids); +} + +/*******************************/ + +bool GPGAuthMgr::isValid(std::string id) +{ + return AuthSSL::isValid(id); +} + +bool GPGAuthMgr::isAuthenticated(std::string id) +{ + /* This must be handled at PGP level */ + + /* get pgpid */ + std::string pgpid = getIssuerName(id); + + return isPGPAuthenticated(pgpid); + //return AuthSSL::isAuthenticated(id); +} + +bool GPGAuthMgr::isTrustingMe(std::string) +{ + return false; +} + +void GPGAuthMgr::addTrustingPeer(std::string) +{ + + +} + +/**** These Two are common */ +std::string GPGAuthMgr::getName(std::string id) +{ + std::string name = AuthSSL::getName(id); + if (name != "") + { + certmap::iterator it; + if (mKeyList.end() != (it = mKeyList.find(id))) + { + return it->second.user.name; + } + } + return name; +} + +bool GPGAuthMgr::getDetails(std::string id, pqiAuthDetails &details) +{ + /**** GPG Details. + * Ids are the SSL id cert ids, so we have to get issuer id (pgpid) + * before we can add any gpg details + ****/ + + if (AuthSSL::getDetails(id, details)) + { + certmap::iterator it; + if (mKeyList.end() != (it = mKeyList.find(details.issuer))) + { + /* what do we want from the gpg mgr */ + details.location = details.name; + details.name = it->second.user.name; + details.email = it->second.user.email; + + //details = it->second.user; + return true; + } + return true; + } + else + { + /* if we cannot find a ssl cert - might be a pgp cert */ + certmap::iterator it; + if (mKeyList.end() != (it = mKeyList.find(id))) + { + /* what do we want from the gpg mgr */ + details = it->second.user; + return true; + } + } + return false; +} + + +/**** GPG versions ***/ + +std::string GPGAuthMgr::PGPOwnId() +{ + return mOwnId; +} + +bool GPGAuthMgr::getPGPAllList(std::list &ids) +{ + /* 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 GPGAuthMgr::getPGPAuthenticatedList(std::list &ids) +{ + certmap::iterator it; + for(it = mKeyList.begin(); it != mKeyList.end(); it++) + { + if (it->second.user.trustLvl > GPGME_VALIDITY_MARGINAL) + { + ids.push_back(it->first); + } + } + return true; +} + +bool GPGAuthMgr::getPGPUnknownList(std::list &ids) +{ + certmap::iterator it; + for(it = mKeyList.begin(); it != mKeyList.end(); it++) + { + if (it->second.user.trustLvl <= GPGME_VALIDITY_MARGINAL) + { + ids.push_back(it->first); + } + } + return true; +} + + +bool GPGAuthMgr::isPGPValid(std::string id) +{ + certmap::iterator it; + return (mKeyList.end() != mKeyList.find(id)); +} + + +bool GPGAuthMgr::isPGPAuthenticated(std::string id) +{ + certmap::iterator it; + if (mKeyList.end() != (it = mKeyList.find(id))) + { + return (it->second.user.trustLvl > GPGME_VALIDITY_FULL); + } + return false; +} + +/****** Large Parts of the p3AuthMgr is provided by AuthSSL ****** + * As the majority of functions require SSL Certs + * + * We don't need to save/load openpgp certificates, as the gpgme + * handles this. + * + */ + +#if 0 + +bool GPGAuthMgr::FinalSaveCertificates() +{ + return false; +} + +bool GPGAuthMgr::CheckSaveCertificates() +{ + return false; +} + +bool GPGAuthMgr::saveCertificates() +{ + return false; +} + +bool GPGAuthMgr::loadCertificates() +{ + return false; +} + +#endif + +/***************************************************************** + * 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 GPGAuthMgr::SaveCertificateToString(std::string id) +{ + if (!isPGPValid(id)) + { + /* check if it is a SSL Certificate */ + if (isValid(id)) + { + std::string sslcert = AuthSSL::SaveCertificateToString(id); + return sslcert; + } + std::string emptystr; + return emptystr; + } + + 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::cerr << 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::cerr << std::endl; + } + + fflush (NULL); + fputs ("Begin Result:\n", stdout); + showData (gpgmeData); + fputs ("End Result.\n", stdout); + + size_t len = 0; + char *export_txt = gpgme_data_release_and_get_mem(gpgmeData, &len); + tmp = std::string(export_txt); + + gpgme_free(export_txt); + + return tmp; +} + +/* import to GnuPG and other Certificates */ +bool GPGAuthMgr::LoadCertificateFromString(std::string str, std::string &id) +{ + /* catch SSL Certs and pass to AuthSSL. */ + std::string sslmarker("-----BEGIN CERTIFICATE-----"); + size_t pos = str.find(sslmarker); + if (pos != std::string::npos) + { + return AuthSSL::LoadCertificateFromString(str, id); + } + + /* otherwise assume it is a PGP cert */ + + gpgme_data_t gpgmeData; + if (GPG_ERR_NO_ERROR != gpgme_data_new_from_mem(&gpgmeData, str.c_str(), str.length(), 1)) + { + std::cerr << "Error create Data"; + std::cerr << std::endl; + } + + /* move string data to gpgmeData */ + + gpgme_set_armor (CTX, 1); + + if (GPG_ERR_NO_ERROR != gpgme_op_import (CTX,gpgmeData)) + { + std::cerr << "GPGAuthMgr::Error Importing Certificate"; + std::cerr << std::endl; + } + + + gpgme_import_result_t res = gpgme_op_import_result(CTX); + + fprintf(stderr, "ImportCertificate(Considered: %d Imported: %d)\n", + res->considered, res->imported); + + fflush (NULL); + fputs ("Begin Result:\n", stdout); + showData (gpgmeData); + fputs ("End Result.\n", stdout); + + gpgme_data_release (gpgmeData); + + /* extract id(s)! */ + + return true; +} + +bool GPGAuthMgr::LoadCertificateFromFile(std::string filename, std::string &id) +{ + return false; +} + +bool GPGAuthMgr::SaveCertificateToFile(std::string id, std::string filename) +{ + return false; +} +bool GPGAuthMgr::LoadCertificateFromBinary(const uint8_t *ptr, uint32_t len, std::string &id) +{ + return false; +} + +bool GPGAuthMgr::SaveCertificateToBinary(std::string id, uint8_t **ptr, uint32_t *len) +{ + return false; +} + +/***************************************************************** + * 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 + * + */ + + +/*************************************/ + +/* Auth takes SSL Certificate */ +bool GPGAuthMgr::AuthCertificate(std::string id) +{ + /** + * we are passed an SSL cert, check if the cert is signed + * by an already authed peer. + **/ + std::cerr << "GPGAuthMgr::AuthCertificate(" << id << ")"; + std::cerr << std::endl; + + std::string pgpid = AuthSSL::getIssuerName(id); + + if (isPGPAuthenticated(pgpid)) + { + return true; + } + + if (!isPGPValid(pgpid)) + { + return false; + } + + return SignCertificate(pgpid); +} + +/* These take PGP Ids */ +bool GPGAuthMgr::SignCertificate(std::string id) +{ + std::cerr << "GPGAuthMgr::SignCertificate(" << id << ")"; + std::cerr << std::endl; + + return false; +} + +bool GPGAuthMgr::RevokeCertificate(std::string id) +{ + std::cerr << "GPGAuthMgr::RevokeCertificate(" << id << ")"; + std::cerr << std::endl; + + return false; +} + +bool GPGAuthMgr::TrustCertificate(std::string id, bool trust) +{ + std::cerr << "GPGAuthMgr::TrustCertificate(" << id << "," << trust << ")"; + std::cerr << std::endl; + + return false; +} + +/***************************************************************** + * Signing data is done by the SSL certificate. + * + */ + +#if 0 + +bool GPGAuthMgr::SignData(std::string input, std::string &sign) +{ + return false; +} + +bool GPGAuthMgr::SignData(const void *data, const uint32_t len, std::string &sign) +{ + return false; +} + + +bool GPGAuthMgr::SignDataBin(std::string input, unsigned char *sign, unsigned int *signlen) +{ + return false; +} + +bool GPGAuthMgr::SignDataBin(const void *data, const uint32_t len, + unsigned char *sign, unsigned int *signlen) +{ + return false; +} + +#endif + + + /************* Virtual Functions from AuthSSL *************/ + +bool GPGAuthMgr::ValidateCertificate(X509 *x509, std::string &peerId) +{ + std::cerr << "GPGAuthMgr::ValidateCertificate()"; + std::cerr << std::endl; + + bool val = AuthX509(x509); + if (val) + { + return getX509id(x509, peerId); + } + + return false; +} + + +int GPGAuthMgr::VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) +{ + char buf[256]; + X509 *err_cert; + int err, depth; + + err_cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + std::cerr << "GPGAuthMgr::VerifyX509Callback(preverify_ok: " << preverify_ok + << " Err: " << err << " Depth: " << depth; + std::cerr << std::endl; + + /* + * Retrieve the pointer to the SSL of the connection currently treated + * and the application specific data stored into the SSL object. + */ + + X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); + + std::cerr << "GPGAuthMgr::VerifyX509Callback: depth: " << depth << ":" << buf; + std::cerr << std::endl; + + + if (!preverify_ok) { + fprintf(stderr, "Verify error:num=%d:%s:depth=%d:%s\n", err, + X509_verify_cert_error_string(err), depth, buf); + } + + /* + * At this point, err contains the last verification error. We can use + * it for something special + */ + + if (!preverify_ok) + { + if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) || + (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) + { + X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256); + printf("issuer= %s\n", buf); + + fprintf(stderr, "Doing REAL PGP Certificates\n"); + /* do the REAL Authentication */ + if (!AuthX509(ctx->current_cert)) + { + return false; + } + std::string pgpid = getX509CNString(ctx->current_cert->cert_info->issuer); + if (!isPGPAuthenticated(pgpid)) + { + return false; + } + preverify_ok = true; + } + else if ((err == X509_V_ERR_CERT_UNTRUSTED) || + (err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) + { + std::string pgpid = getX509CNString(ctx->current_cert->cert_info->issuer); + if (!isPGPAuthenticated(pgpid)) + { + return false; + } + preverify_ok = true; + } + } + else + { + fprintf(stderr, "Failing Normal Certificate!!!\n"); + preverify_ok = false; + } + + return preverify_ok; +} + + + /************* Virtual Functions from AuthSSL *************/ + + + + /* Sign/Trust stuff */ + +int GPGAuthMgr::signCertificate(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 ??? + */ + + certmap::iterator it; + if (mKeyList.end() == (it = mKeyList.find(id))) + { + return false; + } + + gpgme_key_t signKey = it->second.key; + gpgme_key_t ownKey = mOwnGpgCert.key; + + class SignParams sparams("0", passphrase); + 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))) { + return 0; + } + + + if(GPG_ERR_NO_ERROR != (ERR = gpgme_op_edit(CTX, signKey, keySignCallback, \ + ¶ms, out))) { + return 0; + } + + /* Should I move the certificate from Others to Peers ??? */ + + return 1; +} + +/* revoke the signature on Certificate */ +int GPGAuthMgr::revokeCertificate(std::string id) +{ + return 0; +} + +int GPGAuthMgr::trustCertificate(std::string id, int trustlvl) +{ + /* The certificate should be in Peers list ??? */ + + if(!isAuthenticated(id)) { + std::cerr << "Invalid Certificate" << std::endl; + return 0; + } + + gpgcert trustCert = mKeyList.find(id)->second; + gpgme_key_t trustKey = trustCert.key; + const char *lvls[] = {"1", "2", "3", "4", "5"}; + class EditParams params(TRUST_START, (void *) *(lvls + trustlvl -1)); + 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, ¶ms, out))) + return 0; + + return 1; +} + + +/* This function to print Data */ +void GPGAuthMgr::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::cerr << 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::cerr << std::endl; + //fail_if_err (gpgme_err_code_from_errno (errno)); + } +} + +/******************************************************************************/ +/* TEST/DEBUG */ +/******************************************************************************/ +/* + * Create a number of friends and add them to the Map of peers. + * Create a number of friends and add them to the Map of "others" -- people who + * are known but are not allowed to access retroshare + */ +void GPGAuthMgr::createDummyFriends() +{ + const unsigned int DUMMY_KEY_LEN = 2048; + + // create key params for a few dummies + std::string friend1 = setKeyPairParams(true, DUMMY_KEY_LEN, "friend89", + "I am your first friend", "friend1@friend.com", "1234"); + std::string friend2 = setKeyPairParams(true, DUMMY_KEY_LEN, "friend2", + "I am your second friend", "friend2@friend.com", "2345"); + std::string friend3 = setKeyPairParams(true, DUMMY_KEY_LEN, "friend3", + "I am your third friend", "friend3@friend.com", "3456"); + + // params for others + std::string other1 = setKeyPairParams(true, DUMMY_KEY_LEN, "other89", + "I am your first other", "other@other.com", "1234"); + std::string other2 = setKeyPairParams(true, DUMMY_KEY_LEN, "other2", + "I am your second other", "other2@other.com", "2345"); + std::string other3 = setKeyPairParams(true, DUMMY_KEY_LEN, "other3", + "I am your third other", "other3@other.com", "3456"); + + gpgme_error_t rc = GPG_ERR_NO_ERROR; // assume OK + rc = gpgme_op_genkey(CTX, friend1.c_str(), NULL, NULL); + rc = gpgme_op_genkey(CTX, friend2.c_str(), NULL, NULL); + rc = gpgme_op_genkey(CTX, friend3.c_str(), NULL, NULL); + + rc = gpgme_op_genkey(CTX, other1.c_str(), NULL, NULL); + rc = gpgme_op_genkey(CTX, other2.c_str(), NULL, NULL); + rc = gpgme_op_genkey(CTX, other3.c_str(), NULL, NULL); + + std::cout << "createDummyFriends(): exit" << std::endl; + return; +} + +static std::string setKeyPairParams(bool useRsa, unsigned int blen, + std::string name, std::string comment, std::string email, + std::string passphrase) +{ + std::ostringstream params; + params << ""<< std::endl; + if (useRsa) + { + params << "Key-Type: RSA"<< std::endl; + if (blen < 1024) + { + std::cerr << "Weak Key... strengthing..."<< std::endl; + 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: "<< passphrase << std::endl; + params << ""<< std::endl; + + return params.str(); +} + + + +/* Author: Shiva + * This function returns the key macthing the user parameters + * from the keyring + */ + +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)) { + return key; + } + user = user->next; + } + gpgme_key_release (key); + } + + return NULL; +} + + +/* 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; + + 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) { + return params->err; + } + + switch (params->state) + { + case SIGN_START: + 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: + 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_ERROR; + params->err = gpg_error (GPG_ERR_CONFLICT); + } + 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: + 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: + 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: + 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: + if(status == GPGME_STATUS_GET_HIDDEN && + (!std::string("passphrase.enter").compare(args))) + { + params->state = SIGN_CONFIRM; + result = sparams->passphrase.c_str(); + } + else + { + params->state = SIGN_ERROR; + params->err = gpg_error (GPG_ERR_GENERAL); + } + break; + case SIGN_CONFIRM: + 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: + 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: + 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; + } + + if (result) + { + if (*result) + write (fd, result, strlen (result)); + write (fd, "\n", 1); + } + + 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; + const char *result = NULL; + char *trustLvl = (char *)params->oParams; + + 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 = trustLvl; + } 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) + { + if (*result) + write (fd, result, strlen (result)); + write (fd, "\n", 1); + } + + return params->err; +} diff --git a/libretroshare/src/pqi/authgpg.h b/libretroshare/src/pqi/authgpg.h new file mode 100644 index 000000000..fe58e6040 --- /dev/null +++ b/libretroshare/src/pqi/authgpg.h @@ -0,0 +1,378 @@ +/* + * libretroshare/src/ : gpgauthmgr.h + * + * GPG interface for RetroShare. + * + * Copyright 2008-2009 by Raghu Dev R. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of 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". + * + * This is *THE* auth manager. It provides the web-of-trust via + * gpgme, and authenticates the certificates that are managed + * by the sublayer AuthSSL. + * + */ + +#ifndef RS_GPG_AUTH_HEADER +#define RS_GPG_AUTH_HEADER + +//#include "p3authmgr.h" +#include "authssl.h" +#include + +/* gpgcert is the identifier for a person. + * It is a wrapper class for a GPGme OpenPGP certificate. + */ + +class gpgcert +{ + public: + pqiAuthDetails user; + gpgme_key_t key; +}; + +/* + * The certificate map type + */ +typedef std::map certmap; + +class GPGAuthMgr: public AuthSSL +{ + public: + + GPGAuthMgr(); + ~GPGAuthMgr(); + + X509* SignX509Req(X509_REQ *req, long days, std::string); + bool AuthX509(X509 *x509); + + bool DoOwnSignature(void *, unsigned int, void *, unsigned int *); + bool VerifySignature(std::string id, void *data, int datalen, + void *sig, unsigned int siglen); + + bool availablePGPCertificates(std::list &ids); + + int GPGInit(std::string ownId, std::string name, std::string passwd); + int GPGInit(std::string name, std::string comment, + std::string email, std::string passwd); + /* Sign/Trust stuff */ + int signCertificate(std::string id); + int revokeCertificate(std::string id); /* revoke the signature on Certificate */ + int trustCertificate(std::string id, int trustlvl); + + /* SKTAN */ + void showData(gpgme_data_t dh); + void createDummyFriends(void); //NYI + +/*********************************************************************************/ +/************************* STAGE 1 ***********************************************/ +/*********************************************************************************/ +/***** + * STAGE 1: Initialisation.... As we are switching to OpenPGP the init functions + * will be different. Just move the initialisation functions over.... + * + * As GPGMe requires external calls to the GPG executable, which could potentially + * be expensive, We'll want to cache the GPG keys in this class. + * This should be done at initialisation, and saved in a map. + * (see storage at the end of the class) + * + ****/ + + /* initialisation -> done by derived classes */ + bool active(); + + /* Init by generating new Own PGP Cert, or selecting existing PGP Cert + */ + + /* Arguments passed on to AuthSSL */ + int InitAuth(const char *srvr_cert, const char *priv_key, + const char *passwd); + bool CloseAuth(); + // int setConfigDirectories(std::string confFile, std::string neighDir); + +// store all keys in map mKeyList to avoid calling gpgme exe repeatedly + bool storeAllKeys(); + bool updateTrustAllKeys(); + + bool printAllKeys(); + bool printOwnKeys(); + + + +/*********************************************************************************/ +/************************* STAGE 2 ***********************************************/ +/*********************************************************************************/ +/***** + * STAGE 2: These are some of the most commonly used functions in Retroshare. + * + * provide access to the cache list that was created in stage 1. + * + ****/ + + /* get Certificate Ids */ + + std::string OwnId(); + bool getAllList(std::list &ids); + bool getAuthenticatedList(std::list &ids); + bool getUnknownList(std::list &ids); + +/*********************************************************************************/ +/************************* STAGE 3 ***********************************************/ +/*********************************************************************************/ +/***** + * STAGE 3: These are some of the most commonly used functions in Retroshare. + * + * More commonly used functions. + * + * provide access to details in cache list. + * + ****/ + + /* get Details from the Certificates */ + + bool isValid(std::string id); + bool isAuthenticated(std::string id); + std::string getName(std::string id); + bool getDetails(std::string id, pqiAuthDetails &details); + + virtual bool isTrustingMe(std::string); + virtual void addTrustingPeer(std::string); + + + /* PGP versions of Certificate Fns */ + + std::string PGPOwnId(); + bool getPGPAllList(std::list &ids); + bool getPGPAuthenticatedList(std::list &ids); + bool getPGPUnknownList(std::list &ids); + bool isPGPValid(std::string id); + bool isPGPAuthenticated(std::string id); + bool getPGPDetails(std::string id, pqiAuthDetails &details); + +/*********************************************************************************/ +/************************* STAGE 4 ***********************************************/ +/*********************************************************************************/ +/***** + * STAGE 4: Loading and Saving Certificates. (Strings and Files) + * + ****/ + + + /* Load/Save certificates */ + bool LoadCertificateFromString(std::string pem, std::string &id); + std::string SaveCertificateToString(std::string id); + bool LoadCertificateFromFile(std::string filename, std::string &id); + bool SaveCertificateToFile(std::string id, std::string filename); + +/*********************************************************************************/ +/************************* STAGE 5 ***********************************************/ +/*********************************************************************************/ +/***** + * STAGE 5: Loading and Saving Certificates (Binary) + * + * The existing function arguments are based on OpenSSL functions. + * Feel free to change this format if required. + * + ****/ + + + bool LoadCertificateFromBinary(const uint8_t *ptr, uint32_t len, std::string &id); + bool SaveCertificateToBinary(std::string id, uint8_t **ptr, uint32_t *len); + +/*********************************************************************************/ +/************************* STAGE 6 ***********************************************/ +/*********************************************************************************/ +/***** + * STAGE 6: Authentication, Trust and Signing. + * + * This is some of the harder functions, but they should have been + * done in gpgroot already. + * + ****/ + + /* Signatures */ + bool AuthCertificate(std::string uid); + bool SignCertificate(std::string id); + bool RevokeCertificate(std::string id); /* Particularly hard - leave for later */ + bool TrustCertificate(std::string id, bool trust); + +/*********************************************************************************/ +/************************* STAGE 7 ***********************************************/ +/*********************************************************************************/ +/***** + * STAGE 7: Signing Data. + * + * There should also be Encryption Functions... (do later). + * + ****/ + +#if 0 +virtual bool SignData(std::string input, std::string &sign); +virtual bool SignData(const void *data, const uint32_t len, std::string &sign); +virtual bool SignDataBin(std::string input, unsigned char *sign, unsigned int *signlen); +virtual bool SignDataBin(const void *data, const uint32_t len, + unsigned char *sign, unsigned int *signlen); +virtual bool VerifySignBin(std::string, const void*, uint32_t, unsigned char*, unsigned int); + +#endif + + +/*********************************************************************************/ +/************************* PGP Specific functions ********************************/ +/*********************************************************************************/ + +/* + * These support the authentication process. + * + */ + + /************* Virtual Functions from AuthSSL *************/ +virtual bool ValidateCertificate(X509 *x509, std::string &peerId); +virtual int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx); + /************* Virtual Functions from AuthSSL *************/ + +/* + * + */ + +bool checkSignature(std::string id, std::string hash, std::string signature); + + + + +/*********************************************************************************/ +/************************* OTHER FUNCTIONS ***************************************/ +/*********************************************************************************/ + + /* High Level Load/Save Configuration */ +/***** + * These functions call straight through to AuthSSL. + * We don't need these functions here - as GPG stores the keys for us. + bool FinalSaveCertificates(); + bool CheckSaveCertificates(); + bool saveCertificates(); + bool loadCertificates(); + ****/ + + private: + + /* Example Storage - Change as needed */ + + certmap mKeyList; + + bool gpgmeInit; + bool gpgmeKeySelected; + bool gpgmeX509Selected; + + gpgme_engine_info_t INFO; + gpgme_ctx_t CTX; + + std::string mOwnId; + std::string mX509id; + + gpgcert mOwnGpgCert; + + std::string passphrase; +}; + +/***** + * + * Support Functions for OpenSSL verification. + * + */ + +//int verify_pgp_callback(int preverify_ok, X509_STORE_CTX *ctx); + + +/* Sign a key */ + +typedef enum +{ + SIGN_START, + SIGN_COMMAND, + SIGN_UIDS, + SIGN_SET_EXPIRE, + SIGN_SET_CHECK_LEVEL, + SIGN_ENTER_PASSPHRASE, + SIGN_CONFIRM, + SIGN_QUIT, + SIGN_SAVE, + SIGN_ERROR +} SignState; + + +/* Change the key ownertrust */ + +typedef enum +{ + TRUST_START, + TRUST_COMMAND, + TRUST_VALUE, + TRUST_REALLY_ULTIMATE, + TRUST_QUIT, + TRUST_SAVE, + TRUST_ERROR +} TrustState; + + + +/* This is the generic data object passed to the + * callback function in a gpgme_op_edit operation. + * The contents of this object are modified during + * each callback, to keep track of states, errors + * and other data. + */ + +class EditParams +{ + public: + int state; + /* The return code of gpgme_op_edit() is the return value of + * the last invocation of the callback. But returning an error + * from the callback does not abort the edit operation, so we + * must remember any error. + */ + gpg_error_t err; + + /* Parameters specific to the key operation */ + void *oParams; + + EditParams(int state, void *oParams) { + this->state = state; + this->err = gpgme_error(GPG_ERR_NO_ERROR); + this->oParams = oParams; + } + +}; + +/* Data specific to key signing */ + +class SignParams +{ + public: + + std::string checkLvl; + std::string passphrase; + + SignParams(std::string checkLvl, std::string passphrase) { + this->checkLvl = checkLvl; + this->passphrase = passphrase; + } +}; + + +#endif diff --git a/libretroshare/src/pqi/gpgme_tst.c b/libretroshare/src/pqi/gpgme_tst.c new file mode 100644 index 000000000..fac0ce15e --- /dev/null +++ b/libretroshare/src/pqi/gpgme_tst.c @@ -0,0 +1,76 @@ + +#include "pqi/authgpg.h" + +const std::string key_path("./tmp/privkey.pem"); +const std::string passwd("8764"); +const std::string gpg_passwd("aaaa"); +const std::string name("Test X509"); +const std::string email("test@email.com"); +const std::string org("Org"); +const std::string loc("Loc"); +const std::string state("State"); +const std::string country("GB"); + +int main() +{ + /* Init the auth manager */ + + GPGAuthMgr mgr; + + + /* Select which GPG Keys we use */ + + /* print all keys */ + mgr.printAllKeys(); + mgr.printOwnKeys(); + + std::list idList; + mgr.availablePGPCertificates(idList); + + if (idList.size() < 1) + { + fprintf(stderr, "No GPG Certificate to use!\n"); + exit(1); + } + std::string id = idList.front(); + fprintf(stderr, "Using GPG Certificate:%s \n", id.c_str()); + + std::string noname; + mgr.GPGInit(id, "noname", gpg_passwd); + + /* Init SSL library */ + mgr.InitAuth(NULL, NULL, NULL); + + /* then try to generate and sign a X509 certificate */ + int nbits_in = 2048; + std::string errString; + + /* Generate a Certificate Request */ + X509_REQ *req = GenerateX509Req(key_path, passwd, name, email, org, + loc, state, country, nbits_in, errString); + + // setup output. + BIO *bio_out = NULL; + bio_out = BIO_new(BIO_s_file()); + BIO_set_fp(bio_out,stdout,BIO_NOCLOSE); + + /* Print it out */ + int nmflag = 0; + int reqflag = 0; + + X509_REQ_print_ex(bio_out, req, nmflag, reqflag); + + X509 *x509 = mgr.SignX509Req(req, 100, gpg_passwd); + + X509_print_ex(bio_out, x509, nmflag, reqflag); + + BIO_flush(bio_out); + BIO_free(bio_out); + + /* now try to validate it */ + mgr.AuthX509(x509); + + //sleep(10); +} + +