mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
- added encryption / decryption of files and memory
- started implementation of new AuthGPG git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-OpenPGP@5084 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
c27f695a37
commit
b43fb7e8b3
@ -18,7 +18,11 @@ Compilation
|
|||||||
|
|
||||||
Project
|
Project
|
||||||
02 [1] determine what's missing in OpenPGP-SDK
|
02 [1] determine what's missing in OpenPGP-SDK
|
||||||
03 [1] make a separate layer in RS to handle PGP. AuthPGP is too close to libretroshare.
|
03 [3] make a separate layer in RS to handle PGP. AuthPGP is too close to libretroshare.
|
||||||
|
04 [1] write the new AuthGPG class
|
||||||
|
05 [ ] consider removing thread behaviour of AuthGPG
|
||||||
|
06 [ ] remove callback system and services from AuthGPG, since it's not useful anymore
|
||||||
|
07 [ ] make all RS use GPGIdType isntead of std::string.
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
=====
|
=====
|
||||||
|
@ -80,7 +80,7 @@ PGPIdType PGPIdType::fromFingerprint_hex(const std::string& s)
|
|||||||
|
|
||||||
PGPIdType res ;
|
PGPIdType res ;
|
||||||
|
|
||||||
int n=PGPFingerprintType::KEY_FINGERPRINT_SIZE - PGPIdType::KEY_ID_SIZE -1;
|
int n=2*PGPFingerprintType::KEY_FINGERPRINT_SIZE - 2*PGPIdType::KEY_ID_SIZE ;
|
||||||
|
|
||||||
for(int i = 0; i < PGPIdType::KEY_ID_SIZE; ++i)
|
for(int i = 0; i < PGPIdType::KEY_ID_SIZE; ++i)
|
||||||
{
|
{
|
||||||
@ -237,28 +237,29 @@ bool PGPHandler::availableGPGCertificatesWithPrivateKeys(std::list<PGPIdType>& i
|
|||||||
return true ;
|
return true ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static ops_parse_cb_return_t cb_get_passphrase(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo __attribute__((unused)))
|
static ops_parse_cb_return_t cb_get_passphrase(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo __attribute__((unused)))
|
||||||
// {
|
{
|
||||||
// const ops_parser_content_union_t *content=&content_->content;
|
const ops_parser_content_union_t *content=&content_->content;
|
||||||
// // validate_key_cb_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
|
// validate_key_cb_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
|
||||||
// // ops_error_t **errors=ops_parse_cb_get_errors(cbinfo);
|
// ops_error_t **errors=ops_parse_cb_get_errors(cbinfo);
|
||||||
//
|
|
||||||
// switch(content_->tag)
|
switch(content_->tag)
|
||||||
// {
|
{
|
||||||
// case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
|
case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
|
||||||
// /*
|
{
|
||||||
// Doing this so the test can be automated.
|
std::string passwd = getpass("Please enter passwd:") ;
|
||||||
// */
|
*(content->secret_key_passphrase.passphrase)= (char *)ops_mallocz(passwd.length()+1) ;
|
||||||
// *(content->secret_key_passphrase.passphrase)=ops_malloc_passphrase("hello");
|
memcpy(*(content->secret_key_passphrase.passphrase),passwd.c_str(),passwd.length()) ;
|
||||||
// return OPS_KEEP_MEMORY;
|
return OPS_KEEP_MEMORY;
|
||||||
// break;
|
}
|
||||||
//
|
break;
|
||||||
// default:
|
|
||||||
// break;
|
default:
|
||||||
// }
|
break;
|
||||||
//
|
}
|
||||||
// return OPS_RELEASE_MEMORY;
|
|
||||||
// }
|
return OPS_RELEASE_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
bool PGPHandler::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, PGPIdType& pgpId, std::string& errString)
|
bool PGPHandler::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, PGPIdType& pgpId, std::string& errString)
|
||||||
{
|
{
|
||||||
@ -278,7 +279,7 @@ bool PGPHandler::GeneratePGPCertificate(const std::string& name, const std::stri
|
|||||||
|
|
||||||
// 1 - get a passphrase for encrypting.
|
// 1 - get a passphrase for encrypting.
|
||||||
|
|
||||||
std::string passphrase = _passphrase_callback("Please enter passwd for encrypting your key : ") ;
|
std::string passphrase = _passphrase_callback(NULL,PGPIdType(key->key_id).toStdString().c_str(),"Please enter passwd for encrypting your key : ",false) ;
|
||||||
|
|
||||||
// 2 - save the private key encrypted to a temporary memory buffer
|
// 2 - save the private key encrypted to a temporary memory buffer
|
||||||
|
|
||||||
@ -424,6 +425,122 @@ bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,PGPIdType
|
|||||||
return true ;
|
return true ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PGPHandler::encryptTextToFile(const PGPIdType& key_id,const std::string& text,const std::string& outfile)
|
||||||
|
{
|
||||||
|
const char* filename = "armour_nocompress_sign.asc";
|
||||||
|
|
||||||
|
ops_create_info_t *info;
|
||||||
|
int fd = ops_setup_file_write(&info, outfile.c_str(), ops_true);
|
||||||
|
|
||||||
|
const ops_keydata_t *public_key = getPublicKey(key_id) ;
|
||||||
|
|
||||||
|
if(public_key == NULL)
|
||||||
|
{
|
||||||
|
std::cerr << "Cannot get public key of id " << key_id.toStdString() << std::endl;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Cannot write to %s\n", filename);
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
ops_encrypt_stream(info, public_key, NULL, ops_false, ops_true);
|
||||||
|
ops_write(text.c_str(), text.length(), info);
|
||||||
|
ops_writer_close(info);
|
||||||
|
ops_create_info_delete(info);
|
||||||
|
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ops_parse_cb_return_t pgphandler_callback_write_parsed(const ops_parser_content_t *content_, ops_parse_cb_info_t *cbinfo)
|
||||||
|
// {
|
||||||
|
// ops_parser_content_union_t* content =(ops_parser_content_union_t *)&content_->content;
|
||||||
|
// static ops_boolean_t skipping;
|
||||||
|
//
|
||||||
|
// if(content_->tag != OPS_PTAG_CT_UNARMOURED_TEXT && skipping)
|
||||||
|
// {
|
||||||
|
// puts("...end of skip");
|
||||||
|
// skipping=ops_false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// switch(content_->tag)
|
||||||
|
// {
|
||||||
|
// case OPS_PTAG_CT_UNARMOURED_TEXT:
|
||||||
|
// printf("OPS_PTAG_CT_UNARMOURED_TEXT\n");
|
||||||
|
// if(!skipping)
|
||||||
|
// {
|
||||||
|
// puts("Skipping...");
|
||||||
|
// skipping=ops_true;
|
||||||
|
// }
|
||||||
|
// fwrite(content->unarmoured_text.data, 1, content->unarmoured_text.length, stdout);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case OPS_PTAG_CT_PK_SESSION_KEY:
|
||||||
|
// return callback_pk_session_key(content_, cbinfo);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case OPS_PARSER_CMD_GET_SECRET_KEY:
|
||||||
|
// return callback_cmd_get_secret_key(content_, cbinfo);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
|
||||||
|
// // return callback_cmd_get_secret_key_passphrase(content_,cbinfo);
|
||||||
|
// return cbinfo->cryptinfo.cb_get_passphrase(content_, cbinfo);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case OPS_PTAG_CT_LITERAL_DATA_BODY:
|
||||||
|
// return callback_literal_data(content_, cbinfo);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case OPS_PTAG_CT_ARMOUR_HEADER:
|
||||||
|
// case OPS_PTAG_CT_ARMOUR_TRAILER:
|
||||||
|
// case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
|
||||||
|
// case OPS_PTAG_CT_COMPRESSED:
|
||||||
|
// case OPS_PTAG_CT_LITERAL_DATA_HEADER:
|
||||||
|
// case OPS_PTAG_CT_SE_IP_DATA_BODY:
|
||||||
|
// case OPS_PTAG_CT_SE_IP_DATA_HEADER:
|
||||||
|
// case OPS_PTAG_CT_SE_DATA_BODY:
|
||||||
|
// case OPS_PTAG_CT_SE_DATA_HEADER:
|
||||||
|
//
|
||||||
|
// // Ignore these packets
|
||||||
|
// // They're handled in ops_parse_one_packet()
|
||||||
|
// // and nothing else needs to be done
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// // return callback_general(content_,cbinfo);
|
||||||
|
// break;
|
||||||
|
// // fprintf(stderr,"Unexpected packet tag=%d (0x%x)\n",content_->tag,
|
||||||
|
// // content_->tag);
|
||||||
|
// // assert(0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return OPS_RELEASE_MEMORY;
|
||||||
|
// }
|
||||||
|
|
||||||
|
bool PGPHandler::decryptTextFromFile(const PGPIdType& key_id,std::string& text,const std::string& inputfile)
|
||||||
|
{
|
||||||
|
unsigned char *out_buf = NULL ;
|
||||||
|
std::string buf ;
|
||||||
|
|
||||||
|
FILE *f = fopen(inputfile.c_str(),"rb") ;
|
||||||
|
|
||||||
|
char c ;
|
||||||
|
while( (c = getc(f))!= EOF)
|
||||||
|
buf += c;
|
||||||
|
|
||||||
|
fclose(f) ;
|
||||||
|
|
||||||
|
std::cerr << "PGPHandler::decryptTextFromFile: read a file of length " << buf.length() << std::endl;
|
||||||
|
std::cerr << "buf=" << buf << std::endl;
|
||||||
|
|
||||||
|
int out_length ;
|
||||||
|
ops_boolean_t res = ops_decrypt_memory((const unsigned char *)buf.c_str(),buf.length(),&out_buf,&out_length,_secring,ops_true,cb_get_passphrase) ;
|
||||||
|
|
||||||
|
text = std::string((char *)out_buf,out_length) ;
|
||||||
|
return (bool)res ;
|
||||||
|
}
|
||||||
|
|
||||||
bool PGPHandler::SignDataBin(const PGPIdType& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen)
|
bool PGPHandler::SignDataBin(const PGPIdType& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen)
|
||||||
{
|
{
|
||||||
// need to find the key and to decrypt it.
|
// need to find the key and to decrypt it.
|
||||||
@ -436,7 +553,7 @@ bool PGPHandler::SignDataBin(const PGPIdType& id,const void *data, const uint32_
|
|||||||
return false ;
|
return false ;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string passphrase = _passphrase_callback("Please enter passwd:") ;
|
std::string passphrase = _passphrase_callback(NULL,PGPIdType(key->key_id).toStdString().c_str(),"Please enter passwd for encrypting your key : ",false) ;
|
||||||
|
|
||||||
ops_secret_key_t *secret_key = ops_decrypt_secret_key_from_data(key,passphrase.c_str()) ;
|
ops_secret_key_t *secret_key = ops_decrypt_secret_key_from_data(key,passphrase.c_str()) ;
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
// This class implements an abstract pgp handler to be used in RetroShare.
|
// This class implements an abstract pgp handler to be used in RetroShare.
|
||||||
//
|
//
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -12,7 +14,7 @@ extern "C" {
|
|||||||
#include <openpgpsdk/keyring_local.h>
|
#include <openpgpsdk/keyring_local.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::string (*PassphraseCallback)(const std::string& display_msg) ;
|
typedef std::string (*PassphraseCallback)(void *data, const char *uid_hint, const char *passphrase_info, int prev_was_bad) ;
|
||||||
|
|
||||||
class PGPIdType
|
class PGPIdType
|
||||||
{
|
{
|
||||||
@ -82,6 +84,9 @@ class PGPHandler
|
|||||||
bool SignDataBin(const PGPIdType& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen) ;
|
bool SignDataBin(const PGPIdType& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen) ;
|
||||||
bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) ;
|
bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) ;
|
||||||
|
|
||||||
|
bool encryptTextToFile(const PGPIdType& key_id,const std::string& text,const std::string& outfile) ;
|
||||||
|
bool decryptTextFromFile(const PGPIdType& key_id,std::string& text,const std::string& inputfile) ;
|
||||||
|
|
||||||
bool getKeyFingerprint(const PGPIdType& id,PGPFingerprintType& fp) const ;
|
bool getKeyFingerprint(const PGPIdType& id,PGPFingerprintType& fp) const ;
|
||||||
|
|
||||||
// Debug stuff.
|
// Debug stuff.
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "pgphandler.h"
|
#include "pgphandler.h"
|
||||||
|
|
||||||
static std::string passphrase_callback(const std::string& what)
|
static std::string passphrase_callback(void *data,const char *uid_info,const char *what,int prev_was_bad)
|
||||||
{
|
{
|
||||||
return std::string(getpass(what.c_str())) ;
|
return std::string(getpass(what)) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc,char *argv[])
|
int main(int argc,char *argv[])
|
||||||
@ -70,7 +70,8 @@ int main(int argc,char *argv[])
|
|||||||
std::cerr << cert << std::endl;
|
std::cerr << cert << std::endl;
|
||||||
|
|
||||||
std::cerr << "Testing password callback: " << std::endl;
|
std::cerr << "Testing password callback: " << std::endl;
|
||||||
std::string pass = passphrase_callback("Please enter password: ") ;
|
|
||||||
|
std::string pass = passphrase_callback(NULL,newid.toStdString().c_str(),"Please enter password: ",false) ;
|
||||||
|
|
||||||
std::cerr << "Password = \"" << pass << "\"" << std::endl;
|
std::cerr << "Password = \"" << pass << "\"" << std::endl;
|
||||||
|
|
||||||
@ -96,6 +97,26 @@ int main(int argc,char *argv[])
|
|||||||
else
|
else
|
||||||
std::cerr << "Signature verification worked!" << std::endl;
|
std::cerr << "Signature verification worked!" << std::endl;
|
||||||
|
|
||||||
|
std::string outfile = "crypted_toto.pgp" ;
|
||||||
|
std::string text_to_encrypt = "this is a secret message" ;
|
||||||
|
|
||||||
|
std::cerr << "Checking encrypted file creation: streaming chain \"" << text_to_encrypt << "\" to file " << outfile << " with key " << id2.toStdString() << std::endl;
|
||||||
|
|
||||||
|
if(!pgph.encryptTextToFile(id2,text_to_encrypt,outfile))
|
||||||
|
std::cerr << "Encryption failed" << std::endl;
|
||||||
|
else
|
||||||
|
std::cerr << "Encryption success" << std::endl;
|
||||||
|
|
||||||
|
std::string decrypted_text = "" ;
|
||||||
|
outfile = "crypted_toto2.pgp" ;
|
||||||
|
|
||||||
|
if(!pgph.decryptTextFromFile(id2,decrypted_text,outfile))
|
||||||
|
std::cerr << "Decryption failed" << std::endl;
|
||||||
|
else
|
||||||
|
std::cerr << "Decryption success" << std::endl;
|
||||||
|
|
||||||
|
std::cerr << "Decrypted text: \"" << decrypted_text << "\"" << std::endl;
|
||||||
|
|
||||||
return 0 ;
|
return 0 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -50,6 +50,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "pqi/p3cfgmgr.h"
|
#include "pqi/p3cfgmgr.h"
|
||||||
|
#include "pgp/pgphandler.h"
|
||||||
|
|
||||||
#define MAX_GPG_SIGNATURE_SIZE 4096
|
#define MAX_GPG_SIGNATURE_SIZE 4096
|
||||||
|
|
||||||
@ -65,32 +66,49 @@ class gpgcert
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
gpgcert();
|
gpgcert();
|
||||||
~gpgcert();
|
~gpgcert() {}
|
||||||
|
|
||||||
std::string id;
|
std::string id;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string email;
|
std::string email;
|
||||||
|
|
||||||
std::string fpr; /* fingerprint */
|
std::string fpr; /* fingerprint */
|
||||||
std::list<std::string> signers;
|
std::list<std::string> signers;
|
||||||
|
|
||||||
uint32_t trustLvl;
|
uint32_t trustLvl;
|
||||||
uint32_t validLvl;
|
uint32_t validLvl;
|
||||||
|
|
||||||
bool ownsign;
|
bool ownsign;
|
||||||
|
|
||||||
//This is not gpg, but RS data. A gpg peer can be accepted for connecting but not signed.
|
//This is not gpg, but RS data. A gpg peer can be accepted for connecting but not signed.
|
||||||
bool accept_connection;
|
bool accept_connection;
|
||||||
|
|
||||||
gpgme_key_t key;
|
PGPIdType key_id ;
|
||||||
|
|
||||||
// Cached Certificates...
|
// Cached Certificates...
|
||||||
bool mHaveCachedCert;
|
bool mHaveCachedCert;
|
||||||
std::string mCachedCert;
|
std::string mCachedCert;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* The certificate map type
|
||||||
|
*/
|
||||||
|
typedef std::map<std::string, gpgcert> certmap;
|
||||||
|
|
||||||
|
//! provides basic gpg functionality
|
||||||
|
/*!
|
||||||
|
*
|
||||||
|
* This provides retroshare basic gpg functionality and
|
||||||
|
* key/web-of-trust management, also handle cert intialisation for retroshare
|
||||||
|
*/
|
||||||
|
|
||||||
|
// extern void AuthGPGInit();
|
||||||
|
// extern void AuthGPGExit();
|
||||||
|
|
||||||
|
/* The real implementation! */
|
||||||
|
|
||||||
|
|
||||||
class AuthGPGOperation
|
class AuthGPGOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -135,427 +153,288 @@ public:
|
|||||||
virtual void setGPGOperation(AuthGPGOperation *operation) = 0;
|
virtual void setGPGOperation(AuthGPGOperation *operation) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
class AuthGPG: public p3Config, public RsThread, public PGPHandler
|
||||||
* The certificate map type
|
|
||||||
*/
|
|
||||||
typedef std::map<std::string, gpgcert> certmap;
|
|
||||||
|
|
||||||
//! provides basic gpg functionality
|
|
||||||
/*!
|
|
||||||
*
|
|
||||||
* This provides retroshare basic gpg functionality and
|
|
||||||
* key/web-of-trust management, also handle cert intialisation for retroshare
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern void AuthGPGInit();
|
|
||||||
extern void AuthGPGExit();
|
|
||||||
|
|
||||||
class AuthGPG : public RsThread
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
//AuthGPG();
|
|
||||||
|
|
||||||
static AuthGPG *getAuthGPG();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ids list of gpg certificate ids (note, not the actual certificates)
|
|
||||||
*/
|
|
||||||
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<std::string> &ids) = 0;
|
|
||||||
virtual bool printKeys() = 0;
|
|
||||||
|
|
||||||
/*********************************************************************************/
|
|
||||||
/************************* 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)
|
|
||||||
*
|
|
||||||
****/
|
|
||||||
virtual bool active() = 0;
|
|
||||||
|
|
||||||
/* Initialize */
|
|
||||||
virtual bool InitAuth () = 0;
|
|
||||||
|
|
||||||
/* Init by generating new Own PGP Cert, or selecting existing PGP Cert */
|
|
||||||
virtual int GPGInit(const std::string &ownId) = 0;
|
|
||||||
virtual bool CloseAuth() = 0;
|
|
||||||
virtual bool GeneratePGPCertificate(std::string name, std::string email, std::string passwd, std::string &pgpId, std::string &errString) = 0;
|
|
||||||
|
|
||||||
/*********************************************************************************/
|
|
||||||
/************************* 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.
|
|
||||||
*
|
|
||||||
****/
|
|
||||||
virtual std::string getGPGName(const std::string &pgp_id) = 0;
|
|
||||||
virtual std::string getGPGEmail(const std::string &pgp_id) = 0;
|
|
||||||
|
|
||||||
/* PGP web of trust management */
|
|
||||||
virtual std::string getGPGOwnId() = 0;
|
|
||||||
virtual std::string getGPGOwnName() = 0;
|
|
||||||
|
|
||||||
//virtual std::string getGPGOwnEmail() = 0;
|
|
||||||
virtual bool getGPGDetails(const std::string &id, RsPeerDetails &d) = 0;
|
|
||||||
virtual bool getGPGAllList(std::list<std::string> &ids) = 0;
|
|
||||||
virtual bool getGPGValidList(std::list<std::string> &ids) = 0;
|
|
||||||
virtual bool getGPGAcceptedList(std::list<std::string> &ids) = 0;
|
|
||||||
virtual bool getGPGSignedList(std::list<std::string> &ids) = 0;
|
|
||||||
virtual bool isGPGValid(const std::string &id) = 0;
|
|
||||||
virtual bool isGPGSigned(const std::string &id) = 0;
|
|
||||||
virtual bool isGPGAccepted(const std::string &id) = 0;
|
|
||||||
virtual bool isGPGId(const std::string &id) = 0;
|
|
||||||
|
|
||||||
/*********************************************************************************/
|
|
||||||
/************************* STAGE 4 ***********************************************/
|
|
||||||
/*********************************************************************************/
|
|
||||||
/*****
|
|
||||||
* STAGE 4: Loading and Saving Certificates. (Strings and Files)
|
|
||||||
*
|
|
||||||
****/
|
|
||||||
virtual bool LoadCertificateFromString(const std::string &pem, std::string &gpg_id,std::string& error_string) = 0;
|
|
||||||
virtual std::string SaveCertificateToString(const std::string &id,bool include_signatures) = 0;
|
|
||||||
|
|
||||||
/*********************************************************************************/
|
|
||||||
/************************* STAGE 6 ***********************************************/
|
|
||||||
/*********************************************************************************/
|
|
||||||
/*****
|
|
||||||
* STAGE 6: Authentication, Trust and Signing.
|
|
||||||
*
|
|
||||||
* This is some of the harder functions, but they should have been
|
|
||||||
* done in gpgroot already.
|
|
||||||
*
|
|
||||||
****/
|
|
||||||
|
|
||||||
virtual bool AllowConnection(const std::string &gpg_id, bool accept) = 0;
|
|
||||||
|
|
||||||
virtual bool SignCertificateLevel0(const std::string &id) = 0;
|
|
||||||
virtual bool RevokeCertificate(const std::string &id) = 0; /* Particularly hard - leave for later */
|
|
||||||
//virtual bool TrustCertificateNone(std::string id) = 0;
|
|
||||||
//virtual bool TrustCertificateMarginally(std::string id) = 0;
|
|
||||||
//virtual bool TrustCertificateFully(std::string id) = 0;
|
|
||||||
virtual bool TrustCertificate(const std::string &id, int trustlvl) = 0; //trustlvl is 2 for none, 3 for marginal and 4 for full trust
|
|
||||||
|
|
||||||
/*********************************************************************************/
|
|
||||||
/************************* STAGE 7 ***********************************************/
|
|
||||||
/*********************************************************************************/
|
|
||||||
/*****
|
|
||||||
* STAGE 7: Signing Data.
|
|
||||||
*
|
|
||||||
* There should also be Encryption Functions... (do later).
|
|
||||||
*
|
|
||||||
****/
|
|
||||||
//virtual bool SignData(std::string input, std::string &sign) = 0;
|
|
||||||
//virtual bool SignData(const void *data, const uint32_t len, std::string &sign) = 0;
|
|
||||||
//virtual bool SignDataBin(std::string input, unsigned char *sign, unsigned int *signlen) = 0;
|
|
||||||
virtual bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen) = 0;
|
|
||||||
virtual bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const std::string &withfingerprint) = 0;
|
|
||||||
virtual bool decryptText(gpgme_data_t CIPHER, gpgme_data_t PLAIN) = 0;
|
|
||||||
virtual bool encryptText(gpgme_data_t PLAIN, gpgme_data_t CIPHER) = 0;
|
|
||||||
//END of PGP public functions
|
|
||||||
|
|
||||||
/* GPG service */
|
|
||||||
virtual bool addService(AuthGPGService *service) = 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The real implementation! */
|
|
||||||
|
|
||||||
|
|
||||||
class AuthGPGimpl : public AuthGPG, public p3Config
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AuthGPGimpl();
|
static void init(const std::string& path_to_pubring, const std::string& path_to_secring);
|
||||||
~AuthGPGimpl();
|
static AuthGPG *getAuthGPG() { return _instance ; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ids list of gpg certificate ids (note, not the actual certificates)
|
* @param ids list of gpg certificate ids (note, not the actual certificates)
|
||||||
*/
|
*/
|
||||||
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<std::string> &ids);
|
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<std::string> &ids);
|
||||||
|
virtual bool printKeys();
|
||||||
|
|
||||||
virtual bool printKeys();
|
/*********************************************************************************/
|
||||||
|
/************************* 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)
|
||||||
|
*
|
||||||
|
****/
|
||||||
|
virtual bool active();
|
||||||
|
|
||||||
/*********************************************************************************/
|
// /* Initialize */
|
||||||
/************************* STAGE 1 ***********************************************/
|
// virtual bool InitAuth ();
|
||||||
/*********************************************************************************/
|
// virtual bool CloseAuth();
|
||||||
/*****
|
|
||||||
* 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)
|
|
||||||
*
|
|
||||||
****/
|
|
||||||
virtual bool active();
|
|
||||||
|
|
||||||
/* Initialize */
|
/* Init by generating new Own PGP Cert, or selecting existing PGP Cert */
|
||||||
virtual bool InitAuth ();
|
|
||||||
|
|
||||||
/* Init by generating new Own PGP Cert, or selecting existing PGP Cert */
|
virtual int GPGInit(const std::string &ownId);
|
||||||
virtual int GPGInit(const std::string &ownId);
|
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, std::string &pgpId, std::string &errString);
|
||||||
virtual bool CloseAuth();
|
|
||||||
virtual bool GeneratePGPCertificate(std::string name, std::string email, std::string passwd, std::string &pgpId, std::string &errString);
|
|
||||||
|
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/************************* STAGE 3 ***********************************************/
|
/************************* STAGE 3 ***********************************************/
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/*****
|
/*****
|
||||||
* STAGE 3: These are some of the most commonly used functions in Retroshare.
|
* STAGE 3: These are some of the most commonly used functions in Retroshare.
|
||||||
*
|
*
|
||||||
* More commonly used functions.
|
* More commonly used functions.
|
||||||
*
|
*
|
||||||
* provide access to details in cache list.
|
* provide access to details in cache list.
|
||||||
*
|
*
|
||||||
****/
|
****/
|
||||||
virtual std::string getGPGName(const std::string &pgp_id);
|
virtual std::string getGPGName(const std::string &pgp_id);
|
||||||
virtual std::string getGPGEmail(const std::string &pgp_id);
|
virtual std::string getGPGEmail(const std::string &pgp_id);
|
||||||
|
|
||||||
/* PGP web of trust management */
|
/* PGP web of trust management */
|
||||||
virtual std::string getGPGOwnId();
|
virtual std::string getGPGOwnId();
|
||||||
virtual std::string getGPGOwnName();
|
virtual std::string getGPGOwnName();
|
||||||
|
|
||||||
//virtual std::string getGPGOwnEmail();
|
//virtual std::string getGPGOwnEmail();
|
||||||
virtual bool getGPGDetails(const std::string &id, RsPeerDetails &d);
|
virtual bool getGPGDetails(const std::string &id, RsPeerDetails &d);
|
||||||
virtual bool getGPGAllList(std::list<std::string> &ids);
|
virtual bool getGPGAllList(std::list<std::string> &ids);
|
||||||
virtual bool getGPGValidList(std::list<std::string> &ids);
|
virtual bool getGPGValidList(std::list<std::string> &ids);
|
||||||
virtual bool getGPGAcceptedList(std::list<std::string> &ids);
|
virtual bool getGPGAcceptedList(std::list<std::string> &ids);
|
||||||
virtual bool getGPGSignedList(std::list<std::string> &ids);
|
virtual bool getGPGSignedList(std::list<std::string> &ids);
|
||||||
virtual bool isGPGValid(const std::string &id);
|
virtual bool isGPGValid(const std::string &id);
|
||||||
virtual bool isGPGSigned(const std::string &id);
|
virtual bool isGPGSigned(const std::string &id);
|
||||||
virtual bool isGPGAccepted(const std::string &id);
|
virtual bool isGPGAccepted(const std::string &id);
|
||||||
virtual bool isGPGId(const std::string &id);
|
virtual bool isGPGId(const std::string &id);
|
||||||
|
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/************************* STAGE 4 ***********************************************/
|
/************************* STAGE 4 ***********************************************/
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/*****
|
/*****
|
||||||
* STAGE 4: Loading and Saving Certificates. (Strings and Files)
|
* STAGE 4: Loading and Saving Certificates. (Strings and Files)
|
||||||
*
|
*
|
||||||
****/
|
****/
|
||||||
virtual bool LoadCertificateFromString(const std::string &pem, std::string &gpg_id,std::string& error_string);
|
virtual bool LoadCertificateFromString(const std::string &pem, std::string &gpg_id,std::string& error_string);
|
||||||
virtual std::string SaveCertificateToString(const std::string &id,bool include_signatures) ;
|
virtual std::string SaveCertificateToString(const std::string &id,bool include_signatures) ;
|
||||||
|
|
||||||
// Cached certificates.
|
// Cached certificates.
|
||||||
bool cacheGPGCertificate(const std::string &id, const std::string &certificate);
|
bool cacheGPGCertificate(const std::string &id, const std::string &certificate);
|
||||||
bool getCachedGPGCertificate(const std::string &id, std::string &certificate);
|
bool getCachedGPGCertificate(const std::string &id, std::string &certificate);
|
||||||
|
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/************************* STAGE 6 ***********************************************/
|
/************************* STAGE 6 ***********************************************/
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/*****
|
/*****
|
||||||
* STAGE 6: Authentication, Trust and Signing.
|
* STAGE 6: Authentication, Trust and Signing.
|
||||||
*
|
*
|
||||||
* This is some of the harder functions, but they should have been
|
* This is some of the harder functions, but they should have been
|
||||||
* done in gpgroot already.
|
* done in gpgroot already.
|
||||||
*
|
*
|
||||||
****/
|
****/
|
||||||
virtual bool AllowConnection(const std::string &gpg_id, bool accept);
|
virtual bool AllowConnection(const std::string &gpg_id, bool accept);
|
||||||
|
|
||||||
virtual bool SignCertificateLevel0(const std::string &id);
|
virtual bool SignCertificateLevel0(const std::string &id);
|
||||||
virtual bool RevokeCertificate(const std::string &id); /* Particularly hard - leave for later */
|
virtual bool RevokeCertificate(const std::string &id); /* Particularly hard - leave for later */
|
||||||
|
|
||||||
//virtual bool TrustCertificateNone(std::string id);
|
virtual bool TrustCertificate(const std::string &id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust
|
||||||
//virtual bool TrustCertificateMarginally(std::string id);
|
|
||||||
//virtual bool TrustCertificateFully(std::string id);
|
|
||||||
virtual bool TrustCertificate(const std::string &id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust
|
|
||||||
|
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/************************* STAGE 7 ***********************************************/
|
/************************* STAGE 7 ***********************************************/
|
||||||
/*********************************************************************************/
|
/*********************************************************************************/
|
||||||
/*****
|
/*****
|
||||||
* STAGE 7: Signing Data.
|
* STAGE 7: Signing Data.
|
||||||
*
|
*
|
||||||
* There should also be Encryption Functions... (do later).
|
* There should also be Encryption Functions... (do later).
|
||||||
*
|
*
|
||||||
****/
|
****/
|
||||||
//virtual bool SignData(std::string input, std::string &sign);
|
virtual bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen);
|
||||||
//virtual bool SignData(const void *data, const uint32_t len, std::string &sign);
|
virtual bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const std::string &withfingerprint);
|
||||||
//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(const void*, uint32_t, unsigned char*, unsigned int, const std::string &withfingerprint);
|
|
||||||
virtual bool decryptText(gpgme_data_t CIPHER, gpgme_data_t PLAIN);
|
|
||||||
virtual bool encryptText(gpgme_data_t PLAIN, gpgme_data_t CIPHER);
|
|
||||||
//END of PGP public functions
|
|
||||||
|
|
||||||
/* GPG service */
|
virtual bool decryptTextFromFile( std::string& text,const std::string& filename);
|
||||||
virtual bool addService(AuthGPGService *service);
|
virtual bool encryptTextToFile (const std::string& text,const std::string& filename);
|
||||||
|
|
||||||
protected:
|
//END of PGP public functions
|
||||||
/*****************************************************************/
|
|
||||||
/*********************** p3config ******************************/
|
/* GPG service */
|
||||||
/* Key Functions to be overloaded for Full Configuration */
|
virtual bool addService(AuthGPGService *service) { services.push_back(service) ; return true ;}
|
||||||
virtual RsSerialiser *setupSerialiser();
|
|
||||||
virtual bool saveList(bool &cleanup, std::list<RsItem *>&);
|
protected:
|
||||||
virtual bool loadList(std::list<RsItem *>& load);
|
AuthGPG(const std::string& path_to_pubring, const std::string& path_to_secring);
|
||||||
/*****************************************************************/
|
virtual ~AuthGPG();
|
||||||
|
|
||||||
|
/*****************************************************************/
|
||||||
|
/*********************** p3config ******************************/
|
||||||
|
/* Key Functions to be overloaded for Full Configuration */
|
||||||
|
virtual RsSerialiser *setupSerialiser();
|
||||||
|
virtual bool saveList(bool &cleanup, std::list<RsItem *>&);
|
||||||
|
virtual bool loadList(std::list<RsItem *>& load);
|
||||||
|
/*****************************************************************/
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/* SKTAN */
|
/* SKTAN */
|
||||||
//void showData(gpgme_data_t dh);
|
//void showData(gpgme_data_t dh);
|
||||||
//void createDummyFriends(void); //NYI
|
//void createDummyFriends(void); //NYI
|
||||||
|
|
||||||
|
/* Internal functions */
|
||||||
|
bool DoOwnSignature(const void *, unsigned int, void *, unsigned int *);
|
||||||
|
bool VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const std::string &withfingerprint);
|
||||||
|
|
||||||
/* Internal functions */
|
/* Sign/Trust stuff */
|
||||||
bool DoOwnSignature(const void *, unsigned int, void *, unsigned int *);
|
int privateSignCertificate(const std::string &id);
|
||||||
bool VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const std::string &withfingerprint);
|
int privateRevokeCertificate(const std::string &id); /* revoke the signature on Certificate */
|
||||||
|
int privateTrustCertificate(const std::string &id, int trustlvl);
|
||||||
|
|
||||||
/* Sign/Trust stuff */
|
// store all keys in map mKeyList to avoid calling gpgme exe repeatedly
|
||||||
int privateSignCertificate(const std::string &id);
|
//bool storeAllKeys();
|
||||||
int privateRevokeCertificate(const std::string &id); /* revoke the signature on Certificate */
|
//bool storeAllKeys_tick();
|
||||||
int privateTrustCertificate(const std::string &id, int trustlvl);
|
|
||||||
|
|
||||||
// store all keys in map mKeyList to avoid calling gpgme exe repeatedly
|
// Not used anymore
|
||||||
bool storeAllKeys();
|
// bool updateTrustAllKeys_locked();
|
||||||
bool storeAllKeys_tick();
|
|
||||||
|
|
||||||
// Not used anymore
|
/* GPG service */
|
||||||
// bool updateTrustAllKeys_locked();
|
void processServices();
|
||||||
|
|
||||||
/* GPG service */
|
bool printAllKeys_locked();
|
||||||
void processServices();
|
bool printOwnKeys_locked();
|
||||||
|
|
||||||
bool printAllKeys_locked();
|
/* own thread */
|
||||||
bool printOwnKeys_locked();
|
virtual void run();
|
||||||
|
|
||||||
/* own thread */
|
private:
|
||||||
virtual void run();
|
|
||||||
|
|
||||||
private:
|
static AuthGPG *instance_gpg; // pointeur vers le singleton
|
||||||
|
|
||||||
static AuthGPG *instance_gpg; // pointeur vers le singleton
|
RsMutex gpgMtxEngine;
|
||||||
|
/* Below is protected via the mutex */
|
||||||
|
|
||||||
RsMutex gpgMtxEngine;
|
// gpgme_engine_info_t INFO;
|
||||||
/* Below is protected via the mutex */
|
// gpgme_ctx_t CTX;
|
||||||
|
|
||||||
gpgme_engine_info_t INFO;
|
RsMutex gpgMtxData;
|
||||||
gpgme_ctx_t CTX;
|
/* Below is protected via the mutex */
|
||||||
|
|
||||||
RsMutex gpgMtxData;
|
certmap mKeyList;
|
||||||
/* Below is protected via the mutex */
|
time_t mStoreKeyTime;
|
||||||
|
|
||||||
certmap mKeyList;
|
// bool gpgmeInit;
|
||||||
time_t mStoreKeyTime;
|
|
||||||
|
|
||||||
bool gpgmeInit;
|
PGPIdType mOwnGpgId;
|
||||||
|
gpgcert mOwnGpgCert;
|
||||||
|
bool gpgKeySelected;
|
||||||
|
|
||||||
bool gpgmeKeySelected;
|
std::map<std::string, bool> mAcceptToConnectMap;
|
||||||
|
|
||||||
std::string mOwnGpgId;
|
|
||||||
gpgcert mOwnGpgCert;
|
|
||||||
|
|
||||||
std::map<std::string, bool> mAcceptToConnectMap;
|
RsMutex gpgMtxService;
|
||||||
|
std::list<AuthGPGService*> services ;
|
||||||
|
|
||||||
RsMutex gpgMtxService;
|
static AuthGPG *_instance ;
|
||||||
/* Below is protected via the mutex */
|
|
||||||
|
|
||||||
std::list<AuthGPGService*> services;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
SignParams(std::string checkLvl) {
|
|
||||||
this->checkLvl = checkLvl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Data specific to key signing
|
|
||||||
**/
|
|
||||||
class TrustParams
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
std::string trustLvl;
|
|
||||||
|
|
||||||
TrustParams(std::string trustLvl) {
|
|
||||||
this->trustLvl = trustLvl;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
SignParams(std::string checkLvl) {
|
||||||
|
this->checkLvl = checkLvl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Data specific to key signing
|
||||||
|
**/
|
||||||
|
class TrustParams
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
std::string trustLvl;
|
||||||
|
|
||||||
|
TrustParams(std::string trustLvl) {
|
||||||
|
this->trustLvl = trustLvl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -193,5 +193,5 @@ void RsServer::rsGlobalShutDown()
|
|||||||
#endif
|
#endif
|
||||||
#endif // MINIMAL_LIBRS
|
#endif // MINIMAL_LIBRS
|
||||||
|
|
||||||
AuthGPGExit();
|
// AuthGPGExit();
|
||||||
}
|
}
|
||||||
|
@ -612,7 +612,7 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
|
|||||||
*/
|
*/
|
||||||
/* create singletons */
|
/* create singletons */
|
||||||
AuthSSLInit();
|
AuthSSLInit();
|
||||||
AuthGPGInit();
|
//AuthGPGInit();
|
||||||
|
|
||||||
AuthSSL::getAuthSSL() -> InitAuth(NULL, NULL, NULL);
|
AuthSSL::getAuthSSL() -> InitAuth(NULL, NULL, NULL);
|
||||||
|
|
||||||
@ -623,10 +623,10 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
|
|||||||
get_configinit(RsInitConfig::basedir, RsInitConfig::preferedId);
|
get_configinit(RsInitConfig::basedir, RsInitConfig::preferedId);
|
||||||
|
|
||||||
/* Initialize AuthGPG */
|
/* Initialize AuthGPG */
|
||||||
if (AuthGPG::getAuthGPG()->InitAuth() == false) {
|
// if (AuthGPG::getAuthGPG()->InitAuth() == false) {
|
||||||
std::cerr << "AuthGPG::InitAuth failed" << std::endl;
|
// std::cerr << "AuthGPG::InitAuth failed" << std::endl;
|
||||||
return RS_INIT_AUTH_FAILED;
|
// return RS_INIT_AUTH_FAILED;
|
||||||
}
|
// }
|
||||||
|
|
||||||
//std::list<accountId> ids;
|
//std::list<accountId> ids;
|
||||||
std::list<accountId>::iterator it;
|
std::list<accountId>::iterator it;
|
||||||
@ -2314,7 +2314,7 @@ int RsServer::StartupRetroShare()
|
|||||||
|
|
||||||
//mConfigMgr->addConfiguration("ftserver.cfg", ftserver);
|
//mConfigMgr->addConfiguration("ftserver.cfg", ftserver);
|
||||||
//
|
//
|
||||||
mConfigMgr->addConfiguration("gpg_prefs.cfg", (AuthGPGimpl *) AuthGPG::getAuthGPG());
|
mConfigMgr->addConfiguration("gpg_prefs.cfg", AuthGPG::getAuthGPG());
|
||||||
mConfigMgr->loadConfiguration();
|
mConfigMgr->loadConfiguration();
|
||||||
|
|
||||||
mConfigMgr->addConfiguration("peers.cfg", mPeerMgr);
|
mConfigMgr->addConfiguration("peers.cfg", mPeerMgr);
|
||||||
|
@ -634,24 +634,27 @@ bool RsLoginHandler::checkAndStoreSSLPasswdIntoGPGFile(const std::string& ssl_id
|
|||||||
fclose(sslPassphraseFile) ;
|
fclose(sslPassphraseFile) ;
|
||||||
return true ;
|
return true ;
|
||||||
}
|
}
|
||||||
|
fclose(sslPassphraseFile) ;
|
||||||
|
|
||||||
sslPassphraseFile = RsDirUtil::rs_fopen(getSSLPasswdFileName(ssl_id).c_str(), "w");
|
// sslPassphraseFile = RsDirUtil::rs_fopen(getSSLPasswdFileName(ssl_id).c_str(), "w");
|
||||||
|
|
||||||
if(sslPassphraseFile == NULL)
|
// if(sslPassphraseFile == NULL)
|
||||||
{
|
// {
|
||||||
std::cerr << "RsLoginHandler::storeSSLPasswdIntoGPGFile(): could not write to file " << getSSLPasswdFileName(ssl_id) << std::endl;
|
// std::cerr << "RsLoginHandler::storeSSLPasswdIntoGPGFile(): could not write to file " << getSSLPasswdFileName(ssl_id) << std::endl;
|
||||||
return false ;
|
// return false ;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
std::cerr << "openned sslPassphraseFile : " << getSSLPasswdFileName(ssl_id) << std::endl;
|
// std::cerr << "openned sslPassphraseFile : " << getSSLPasswdFileName(ssl_id) << std::endl;
|
||||||
|
//
|
||||||
gpgme_data_t cipher;
|
// gpgme_data_t cipher;
|
||||||
gpgme_data_t plain;
|
// gpgme_data_t plain;
|
||||||
gpgme_data_new_from_mem(&plain, ssl_passwd.c_str(), ssl_passwd.length(), 1);
|
// gpgme_data_new_from_mem(&plain, ssl_passwd.c_str(), ssl_passwd.length(), 1);
|
||||||
gpgme_data_new_from_stream (&cipher, sslPassphraseFile);
|
// gpgme_data_new_from_stream (&cipher, sslPassphraseFile);
|
||||||
|
|
||||||
bool ok ;
|
bool ok ;
|
||||||
if (0 < AuthGPG::getAuthGPG()->encryptText(plain, cipher))
|
std::string cipher ;
|
||||||
|
|
||||||
|
if(AuthGPG::getAuthGPG()->encryptTextToFile(ssl_passwd, getSSLPasswdFileName(ssl_id)))
|
||||||
{
|
{
|
||||||
std::cerr << "Encrypting went ok !" << std::endl;
|
std::cerr << "Encrypting went ok !" << std::endl;
|
||||||
ok= true ;
|
ok= true ;
|
||||||
@ -662,10 +665,9 @@ bool RsLoginHandler::checkAndStoreSSLPasswdIntoGPGFile(const std::string& ssl_id
|
|||||||
ok= false ;
|
ok= false ;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpgme_data_release (cipher);
|
// gpgme_data_release (cipher);
|
||||||
gpgme_data_release (plain);
|
// gpgme_data_release (plain);
|
||||||
|
// fclose(sslPassphraseFile);
|
||||||
fclose(sslPassphraseFile);
|
|
||||||
|
|
||||||
return ok ;
|
return ok ;
|
||||||
}
|
}
|
||||||
@ -685,31 +687,34 @@ bool RsLoginHandler::getSSLPasswdFromGPGFile(const std::string& ssl_id,std::stri
|
|||||||
|
|
||||||
std::cerr << "opening sslPassphraseFile : " << getSSLPasswdFileName(ssl_id).c_str() << std::endl;
|
std::cerr << "opening sslPassphraseFile : " << getSSLPasswdFileName(ssl_id).c_str() << std::endl;
|
||||||
|
|
||||||
gpgme_data_t cipher;
|
// gpgme_data_t cipher;
|
||||||
gpgme_data_t plain;
|
// gpgme_data_t plain;
|
||||||
gpgme_data_new (&plain);
|
// gpgme_data_new (&plain);
|
||||||
|
|
||||||
if( gpgme_data_new_from_stream (&cipher, sslPassphraseFile) != GPG_ERR_NO_ERROR)
|
// if( gpgme_data_new_from_stream (&cipher, sslPassphraseFile) != GPG_ERR_NO_ERROR)
|
||||||
{
|
// {
|
||||||
std::cerr << "Error while creating stream from ssl passwd file." << std::endl ;
|
// std::cerr << "Error while creating stream from ssl passwd file." << std::endl ;
|
||||||
return 0 ;
|
// return 0 ;
|
||||||
}
|
// }
|
||||||
if (0 < AuthGPG::getAuthGPG()->decryptText(cipher, plain))
|
|
||||||
|
std::string plain ;
|
||||||
|
|
||||||
|
if (AuthGPG::getAuthGPG()->decryptTextFromFile(plain,getSSLPasswdFileName(ssl_id)))
|
||||||
{
|
{
|
||||||
std::cerr << "Decrypting went ok !" << std::endl;
|
std::cerr << "Decrypting went ok !" << std::endl;
|
||||||
gpgme_data_write (plain, "", 1);
|
// gpgme_data_write (plain, "", 1);
|
||||||
sslPassword = std::string(gpgme_data_release_and_get_mem(plain, NULL));
|
// sslPassword = std::string(gpgme_data_release_and_get_mem(plain, NULL));
|
||||||
std::cerr << "sslpassword: " << "********************" << std::endl;
|
std::cerr << "sslpassword: " << "********************" << std::endl;
|
||||||
gpgme_data_release (cipher);
|
// gpgme_data_release (cipher);
|
||||||
fclose(sslPassphraseFile);
|
// fclose(sslPassphraseFile);
|
||||||
|
|
||||||
return true ;
|
return true ;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gpgme_data_release (plain);
|
// gpgme_data_release (plain);
|
||||||
gpgme_data_release (cipher);
|
// gpgme_data_release (cipher);
|
||||||
fclose(sslPassphraseFile);
|
// fclose(sslPassphraseFile);
|
||||||
sslPassword = "" ;
|
sslPassword = "" ;
|
||||||
std::cerr << "Error : decrypting went wrong !" << std::endl;
|
std::cerr << "Error : decrypting went wrong !" << std::endl;
|
||||||
|
|
||||||
|
@ -865,28 +865,6 @@ void p3disc::recvDiscReply(RsDiscReply *dri)
|
|||||||
|
|
||||||
void p3disc::removeFriend(std::string /*ssl_id*/)
|
void p3disc::removeFriend(std::string /*ssl_id*/)
|
||||||
{
|
{
|
||||||
|
|
||||||
// DON'T KNOW WHY SSL IDS were saved -> the results are never used
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
#ifdef P3DISC_DEBUG
|
|
||||||
std::cerr << "p3disc::removeFriend() called for : " << ssl_id << std::endl;
|
|
||||||
#endif
|
|
||||||
//if we deleted the gpg_id, don't store the friend deletion as if we add back the gpg_id, we won't have the ssl friends back
|
|
||||||
std::string gpg_id = rsPeers->getGPGId(ssl_id);
|
|
||||||
#ifdef P3DISC_DEBUG
|
|
||||||
std::cerr << "p3disc::removeFriend() gpg_id : " << gpg_id << std::endl;
|
|
||||||
#endif
|
|
||||||
if (gpg_id == AuthGPG::getAuthGPG()->getGPGOwnId() || rsPeers->isGPGAccepted(rsPeers->getGPGId(ssl_id))) {
|
|
||||||
#ifdef P3DISC_DEBUG
|
|
||||||
std::cerr << "p3disc::removeFriend() storing the friend deletion." << ssl_id << std::endl;
|
|
||||||
#endif
|
|
||||||
deletedSSLFriendsIds[ssl_id] = time(NULL);//just keep track of the deleted time
|
|
||||||
IndicateConfigChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************************/
|
/*************************************************************************************/
|
||||||
|
@ -173,7 +173,7 @@ void ops_writer_push_encrypt(ops_create_info_t *info,
|
|||||||
ops_boolean_t ops_encrypt_file(const char* input_filename, const char* output_filename, const ops_keydata_t *pub_key, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite);
|
ops_boolean_t ops_encrypt_file(const char* input_filename, const char* output_filename, const ops_keydata_t *pub_key, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite);
|
||||||
ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_filename, ops_keyring_t *keyring, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite,ops_parse_cb_t* cb_get_passphrase);
|
ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_filename, ops_keyring_t *keyring, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite,ops_parse_cb_t* cb_get_passphrase);
|
||||||
extern void ops_encrypt_stream(ops_create_info_t* cinfo, const ops_keydata_t* public_key, const ops_secret_key_t* secret_key, const ops_boolean_t compress, const ops_boolean_t use_armour);
|
extern void ops_encrypt_stream(ops_create_info_t* cinfo, const ops_keydata_t* public_key, const ops_secret_key_t* secret_key, const ops_boolean_t compress, const ops_boolean_t use_armour);
|
||||||
|
ops_boolean_t ops_decrypt_memory(const unsigned char *encrypted_memory,int em_length, unsigned char **decrypted_memory,int *out_length, ops_keyring_t* keyring, const ops_boolean_t use_armour, ops_parse_cb_t* cb_get_passphrase) ;
|
||||||
// Keys
|
// Keys
|
||||||
ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e, ops_keydata_t* keydata);
|
ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e, ops_keydata_t* keydata);
|
||||||
ops_keydata_t* ops_rsa_create_selfsigned_keypair(const int numbits, const unsigned long e, ops_user_id_t * userid);
|
ops_keydata_t* ops_rsa_create_selfsigned_keypair(const int numbits, const unsigned long e, ops_user_id_t * userid);
|
||||||
|
@ -269,6 +269,91 @@ extern void ops_encrypt_stream(ops_create_info_t* cinfo,
|
|||||||
ops_writer_push_literal(cinfo);
|
ops_writer_push_literal(cinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\ingroup HighLevel_Crypto
|
||||||
|
\brief Decrypt a chunk of memory, containing a encrypted stream.
|
||||||
|
\param input_filename Name of file to be decrypted
|
||||||
|
\param output_filename Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
|
||||||
|
\param keyring Keyring to use
|
||||||
|
\param use_armour Expect armoured text, if set
|
||||||
|
\param allow_overwrite Allow output file to overwritten, if set.
|
||||||
|
\param cb_get_passphrase Callback to use to get passphrase
|
||||||
|
*/
|
||||||
|
|
||||||
|
ops_boolean_t ops_decrypt_memory(const unsigned char *encrypted_memory,int em_length,
|
||||||
|
unsigned char **decrypted_memory,int *out_length,
|
||||||
|
ops_keyring_t* keyring,
|
||||||
|
const ops_boolean_t use_armour,
|
||||||
|
ops_parse_cb_t* cb_get_passphrase)
|
||||||
|
{
|
||||||
|
int fd_in=0;
|
||||||
|
int fd_out=0;
|
||||||
|
char* myfilename=NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
ops_parse_info_t *pinfo=NULL;
|
||||||
|
|
||||||
|
// setup for reading from given input file
|
||||||
|
|
||||||
|
ops_memory_t *input_mem = ops_memory_new() ;
|
||||||
|
ops_memory_add(input_mem,encrypted_memory,em_length) ;
|
||||||
|
|
||||||
|
ops_setup_memory_read(&pinfo, input_mem, NULL, callback_write_parsed, ops_false);
|
||||||
|
|
||||||
|
if (pinfo == NULL)
|
||||||
|
{
|
||||||
|
perror("cannot create memory read");
|
||||||
|
return ops_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup memory chunk
|
||||||
|
|
||||||
|
ops_memory_t *output_mem = ops_memory_new() ;
|
||||||
|
|
||||||
|
ops_setup_memory_write(&pinfo->cbinfo.cinfo, &output_mem,0) ;
|
||||||
|
|
||||||
|
if (output_mem == NULL)
|
||||||
|
{
|
||||||
|
perror("Cannot create output memory");
|
||||||
|
ops_teardown_memory_read(pinfo, input_mem);
|
||||||
|
return ops_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// \todo check for suffix matching armour param
|
||||||
|
|
||||||
|
// setup keyring and passphrase callback
|
||||||
|
pinfo->cbinfo.cryptinfo.keyring=keyring;
|
||||||
|
pinfo->cbinfo.cryptinfo.cb_get_passphrase=cb_get_passphrase;
|
||||||
|
|
||||||
|
// Set up armour/passphrase options
|
||||||
|
|
||||||
|
if (use_armour)
|
||||||
|
ops_reader_push_dearmour(pinfo);
|
||||||
|
|
||||||
|
// Do it
|
||||||
|
|
||||||
|
ops_parse_and_print_errors(pinfo);
|
||||||
|
|
||||||
|
// Unsetup
|
||||||
|
|
||||||
|
if (use_armour)
|
||||||
|
ops_reader_pop_dearmour(pinfo);
|
||||||
|
|
||||||
|
ops_boolean_t res = ops_true ;
|
||||||
|
|
||||||
|
// copy output memory to supplied buffer.
|
||||||
|
//
|
||||||
|
*out_length = ops_memory_get_length(output_mem) ;
|
||||||
|
*decrypted_memory = ops_mallocz(*out_length) ;
|
||||||
|
memcpy(*decrypted_memory,ops_memory_get_data(output_mem),*out_length) ;
|
||||||
|
|
||||||
|
ops_decrypt_memory_ABORT:
|
||||||
|
ops_teardown_memory_write(pinfo->cbinfo.cinfo, output_mem);
|
||||||
|
ops_teardown_memory_read(pinfo, input_mem);
|
||||||
|
|
||||||
|
return res ;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\ingroup HighLevel_Crypto
|
\ingroup HighLevel_Crypto
|
||||||
\brief Decrypt a file.
|
\brief Decrypt a file.
|
||||||
@ -286,7 +371,7 @@ ops_boolean_t ops_decrypt_file(const char* input_filename,
|
|||||||
const ops_boolean_t use_armour,
|
const ops_boolean_t use_armour,
|
||||||
const ops_boolean_t allow_overwrite,
|
const ops_boolean_t allow_overwrite,
|
||||||
ops_parse_cb_t* cb_get_passphrase)
|
ops_parse_cb_t* cb_get_passphrase)
|
||||||
{
|
{
|
||||||
int fd_in=0;
|
int fd_in=0;
|
||||||
int fd_out=0;
|
int fd_out=0;
|
||||||
char* myfilename=NULL;
|
char* myfilename=NULL;
|
||||||
@ -379,8 +464,7 @@ ops_boolean_t ops_decrypt_file(const char* input_filename,
|
|||||||
// \todo cleardown crypt
|
// \todo cleardown crypt
|
||||||
|
|
||||||
return ops_true;
|
return ops_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ops_parse_cb_return_t
|
static ops_parse_cb_return_t
|
||||||
callback_write_parsed(const ops_parser_content_t *content_,
|
callback_write_parsed(const ops_parser_content_t *content_,
|
||||||
ops_parse_cb_info_t *cbinfo)
|
ops_parse_cb_info_t *cbinfo)
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
static int debug=0;
|
static int debug=0;
|
||||||
|
|
||||||
#define LINE_LENGTH 75
|
#define LINE_LENGTH 63
|
||||||
|
|
||||||
static const char newline[] = "\r\n";
|
static const char newline[] = "\r\n";
|
||||||
|
|
||||||
|
@ -34,16 +34,11 @@ linux-* {
|
|||||||
#CONFIG += version_detail_bash_script
|
#CONFIG += version_detail_bash_script
|
||||||
QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64
|
QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64
|
||||||
|
|
||||||
system(which gpgme-config >/dev/null 2>&1) {
|
|
||||||
INCLUDEPATH += $$system(gpgme-config --cflags | sed -e "s/-I//g")
|
|
||||||
} else {
|
|
||||||
message(Could not find gpgme-config on your system, assuming gpgme.h is in /usr/include)
|
|
||||||
}
|
|
||||||
|
|
||||||
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
|
PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a
|
||||||
|
|
||||||
LIBS += ../../libretroshare/src/lib/libretroshare.a
|
LIBS += ../../libretroshare/src/lib/libretroshare.a
|
||||||
LIBS += -lssl -lgpgme -lupnp -lixml -lXss -lgnome-keyring
|
LIBS += ../../openpgpsdk/lib/libops.a -lbz2
|
||||||
|
LIBS += -lssl -lupnp -lixml -lXss -lgnome-keyring
|
||||||
LIBS *= -rdynamic
|
LIBS *= -rdynamic
|
||||||
DEFINES *= HAVE_XSS # for idle time, libx screensaver extensions
|
DEFINES *= HAVE_XSS # for idle time, libx screensaver extensions
|
||||||
DEFINES *= UBUNTU
|
DEFINES *= UBUNTU
|
||||||
|
Loading…
Reference in New Issue
Block a user