mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-01-26 23:36:59 -05:00
Merge pull request #1559 from G10h4ck/autssl_refinement
Cleanup huge amount of AuthSSL and related files cruft
This commit is contained in:
commit
ebd55b2626
@ -1197,37 +1197,7 @@ bool PGPHandler::locked_addOrMergeKey(ops_keyring_t *keyring,std::map<RsPgpId,PG
|
||||
|
||||
return ret ;
|
||||
}
|
||||
// bool PGPHandler::encryptTextToString(const RsPgpId& key_id,const std::string& text,std::string& outstring)
|
||||
// {
|
||||
// RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures.
|
||||
//
|
||||
// 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(public_key->type != OPS_PTAG_CT_PUBLIC_KEY)
|
||||
// {
|
||||
// std::cerr << "PGPHandler::encryptTextToFile(): ERROR: supplied id did not return a public key!" << std::endl;
|
||||
// return false ;
|
||||
// }
|
||||
//
|
||||
// ops_create_info_t *info;
|
||||
// ops_memory_t *buf = NULL ;
|
||||
// ops_setup_memory_write(&info, &buf, 0);
|
||||
//
|
||||
// ops_encrypt_stream(info, public_key, NULL, ops_false, ops_true);
|
||||
// ops_write(text.c_str(), text.length(), info);
|
||||
// ops_writer_close(info);
|
||||
//
|
||||
// outstring = std::string((char *)ops_memory_get_data(buf),ops_memory_get_length(buf)) ;
|
||||
// ops_create_info_delete(info);
|
||||
//
|
||||
// return true ;
|
||||
// }
|
||||
|
||||
bool PGPHandler::encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile)
|
||||
{
|
||||
RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures.
|
||||
@ -2129,4 +2099,3 @@ bool PGPHandler::removeKeysFromPGPKeyring(const std::set<RsPgpId>& keys_to_remov
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,6 @@
|
||||
*******************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
// This class implements an abstract pgp handler to be used in RetroShare.
|
||||
//
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
@ -80,6 +76,7 @@ class PGPCertificateInfo
|
||||
static const uint8_t PGP_CERTIFICATE_TYPE_RSA = 0x02 ;
|
||||
};
|
||||
|
||||
/// This class offer an abstract pgp handler to be used in RetroShare.
|
||||
class PGPHandler
|
||||
{
|
||||
public:
|
||||
@ -125,8 +122,6 @@ class PGPHandler
|
||||
|
||||
bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) ;
|
||||
bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) ;
|
||||
//bool encryptTextToString(const RsPgpId& key_id,const std::string& text,std::string& outstring) ;
|
||||
//bool decryptTextFromString(const RsPgpId& key_id,const std::string& encrypted_text,std::string& outstring) ;
|
||||
|
||||
bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const ;
|
||||
void setAcceptConnexion(const RsPgpId&,bool) ;
|
||||
@ -232,4 +227,3 @@ class PGPHandler
|
||||
static PassphraseCallback _passphrase_callback ;
|
||||
static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,8 @@
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2004-2008 by Robert Fernie, Retroshare Team. *
|
||||
* Copyright (C) 2004-2008 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -19,21 +20,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifndef MRK_AUTH_SSL_HEADER
|
||||
#define MRK_AUTH_SSL_HEADER
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* This is an implementation of SSL certificate authentication, which is
|
||||
* overloaded with pgp style signatures, and web-of-trust authentication.
|
||||
*
|
||||
* only the owner ssl cert is store, the rest is jeus callback verification
|
||||
*
|
||||
* To use as an SSL authentication system, you must use a common CA certificate.
|
||||
* * The pqissl stuff doesn't need to differentiate between SSL, SSL + PGP,
|
||||
* as its X509 certs.
|
||||
* * The rsserver stuff has to distinguish between all three types ;(
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
@ -42,197 +30,263 @@
|
||||
#include <map>
|
||||
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
#include "pqi/pqi_base.h"
|
||||
#include "pqi/pqinetwork.h"
|
||||
#include "pqi/p3cfgmgr.h"
|
||||
#include "util/rsmemory.h"
|
||||
#include "retroshare/rsevents.h"
|
||||
|
||||
/* This #define removes Connection Manager references in AuthSSL.
|
||||
* They should not be here. What about Objects and orthogonality?
|
||||
* This code is also stopping immediate reconnections from working.
|
||||
/**
|
||||
* Functions to interact elegantly with X509 certificates, using this functions
|
||||
* you can avoid annoying #ifdef *SSL_VERSION_NUMBER all around the code.
|
||||
* Function names should be self descriptive.
|
||||
*/
|
||||
|
||||
class AuthSSL;
|
||||
|
||||
class sslcert
|
||||
namespace RsX509Cert
|
||||
{
|
||||
public:
|
||||
sslcert(X509* x509, const RsPeerId& id);
|
||||
sslcert();
|
||||
|
||||
/* certificate parameters */
|
||||
RsPeerId id;
|
||||
std::string name;
|
||||
std::string location;
|
||||
std::string org;
|
||||
std::string email;
|
||||
|
||||
RsPgpId issuer;
|
||||
PGPFingerprintType fpr;
|
||||
|
||||
/* Auth settings */
|
||||
bool authed;
|
||||
|
||||
/* INTERNAL Parameters */
|
||||
X509* certificate;
|
||||
std::string getCertName(const X509& x509);
|
||||
std::string getCertLocation(const X509& x509);
|
||||
std::string getCertOrg(const X509& x509);
|
||||
RsPgpId getCertIssuer(const X509& x509);
|
||||
std::string getCertIssuerString(const X509& x509);
|
||||
RsPeerId getCertSslId(const X509& x509);
|
||||
const EVP_PKEY* getPubKey(const X509& x509);
|
||||
};
|
||||
|
||||
/* required to install instance */
|
||||
/**
|
||||
* Event triggered by AuthSSL when authentication of a connection attempt either
|
||||
* fail or success
|
||||
*/
|
||||
struct RsAuthSslConnectionAutenticationEvent : RsEvent
|
||||
{
|
||||
RsAuthSslConnectionAutenticationEvent();
|
||||
|
||||
bool mSuccess;
|
||||
RsPeerId mSslId;
|
||||
std::string mSslCn;
|
||||
RsPgpId mPgpId;
|
||||
std::string mErrorMsg;
|
||||
|
||||
///* @see RsEvent @see RsSerializable
|
||||
void serial_process( RsGenericSerializer::SerializeJob j,
|
||||
RsGenericSerializer::SerializeContext& ctx) override
|
||||
{
|
||||
RsEvent::serial_process(j, ctx);
|
||||
RS_SERIAL_PROCESS(mSuccess);
|
||||
RS_SERIAL_PROCESS(mSslId);
|
||||
RS_SERIAL_PROCESS(mSslCn);
|
||||
RS_SERIAL_PROCESS(mPgpId);
|
||||
RS_SERIAL_PROCESS(mErrorMsg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This is an implementation of SSL certificate authentication with PGP
|
||||
* signatures, instead of centralized certification authority.
|
||||
*/
|
||||
class AuthSSL
|
||||
{
|
||||
public:
|
||||
AuthSSL();
|
||||
public:
|
||||
static AuthSSL& instance();
|
||||
|
||||
static AuthSSL *getAuthSSL();
|
||||
static void AuthSSLInit();
|
||||
RS_DEPRECATED_FOR(AuthSSL::instance())
|
||||
static AuthSSL* getAuthSSL();
|
||||
|
||||
/* Initialisation Functions (Unique) */
|
||||
virtual bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) = 0;
|
||||
/* Initialisation Functions (Unique) */
|
||||
virtual bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) = 0;
|
||||
|
||||
virtual bool active() = 0;
|
||||
virtual int InitAuth(const char *srvr_cert, const char *priv_key,
|
||||
const char *passwd, std::string alternative_location_name) = 0;
|
||||
virtual bool CloseAuth() = 0;
|
||||
virtual bool active() = 0;
|
||||
virtual int InitAuth(
|
||||
const char* srvr_cert, const char* priv_key, const char* passwd,
|
||||
std::string alternative_location_name ) = 0;
|
||||
virtual bool CloseAuth() = 0;
|
||||
|
||||
/*********** Overloaded Functions from p3AuthMgr **********/
|
||||
|
||||
/* get Certificate Id */
|
||||
virtual const RsPeerId& OwnId() = 0;
|
||||
virtual std::string getOwnLocation() = 0;
|
||||
|
||||
/* get Certificate Id */
|
||||
virtual const RsPeerId& OwnId() = 0;
|
||||
virtual std::string getOwnLocation() = 0;
|
||||
|
||||
/* Load/Save certificates */
|
||||
virtual std::string SaveOwnCertificateToString() = 0;
|
||||
|
||||
virtual std::string SaveOwnCertificateToString() = 0;
|
||||
|
||||
/* Sign / Encrypt / Verify Data */
|
||||
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 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, unsigned char*, unsigned int*) = 0;
|
||||
virtual bool SignDataBin(const void*, uint32_t, unsigned char*, unsigned int*) = 0;
|
||||
virtual bool VerifyOwnSignBin(const void*, uint32_t, unsigned char*, unsigned int) = 0;
|
||||
virtual bool VerifySignBin(const void *data, const uint32_t len,
|
||||
unsigned char *sign, unsigned int signlen, const RsPeerId& sslId) = 0;
|
||||
virtual bool SignDataBin(std::string, unsigned char*, unsigned int*) = 0;
|
||||
virtual bool SignDataBin(
|
||||
const void*, uint32_t, unsigned char*, unsigned int* ) = 0;
|
||||
virtual bool VerifyOwnSignBin(
|
||||
const void*, uint32_t, unsigned char*, unsigned int ) = 0;
|
||||
virtual bool VerifySignBin(
|
||||
const void* data, const uint32_t len, unsigned char* sign,
|
||||
unsigned int signlen, const RsPeerId& sslId ) = 0;
|
||||
|
||||
// return : false if encrypt failed
|
||||
virtual bool encrypt(void *&out, int &outlen, const void *in, int inlen, const RsPeerId& peerId) = 0;
|
||||
// return : false if decrypt fails
|
||||
virtual bool decrypt(void *&out, int &outlen, const void *in, int inlen) = 0;
|
||||
/// return false if failed
|
||||
virtual bool encrypt(
|
||||
void*& out, int& outlen, const void* in, int inlen,
|
||||
const RsPeerId& peerId ) = 0;
|
||||
/// return false if failed
|
||||
virtual bool decrypt(void*& out, int& outlen, const void* in, int inlen) = 0;
|
||||
|
||||
virtual X509* SignX509ReqWithGPG(X509_REQ* req, long days) = 0;
|
||||
|
||||
/**
|
||||
* @brief Verify PGP signature correcteness on given X509 certificate
|
||||
* Beware this doesn't check if the PGP signer is friend or not, just if the
|
||||
* signature is valid!
|
||||
* @param[in] x509 pointer ti the X509 certificate to check
|
||||
* @param[out] diagnostic one of RS_SSL_HANDSHAKE_DIAGNOSTIC_* diagnostic
|
||||
* codes
|
||||
* @return true if correctly signed, false otherwise
|
||||
*/
|
||||
virtual bool AuthX509WithGPG(
|
||||
X509* x509,
|
||||
uint32_t& diagnostic = RS_DEFAULT_STORAGE_PARAM(uint32_t)
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* @brief Callback provided to OpenSSL to authenticate connections
|
||||
* This is the ultimate place where connection attempts get accepted
|
||||
* if authenticated or refused if not authenticated.
|
||||
* Emits @see RsAuthSslConnectionAutenticationEvent.
|
||||
* @param preverify_ok passed by OpenSSL ignored as this call is the first
|
||||
* in the authentication callback chain
|
||||
* @param ctx OpenSSL connection context
|
||||
* @return 0 if authentication failed, 1 if success see OpenSSL
|
||||
* documentation
|
||||
*/
|
||||
virtual int VerifyX509Callback(int preverify_ok, X509_STORE_CTX* ctx) = 0;
|
||||
|
||||
/// SSL specific functions used in pqissl/pqissllistener
|
||||
virtual SSL_CTX* getCTX() = 0;
|
||||
|
||||
virtual void setCurrentConnectionAttemptInfo(
|
||||
const RsPgpId& gpg_id, const RsPeerId& ssl_id,
|
||||
const std::string& ssl_cn ) = 0;
|
||||
virtual void getCurrentConnectionAttemptInfo(
|
||||
RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn ) = 0;
|
||||
|
||||
|
||||
virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days) = 0;
|
||||
virtual bool AuthX509WithGPG(X509 *x509,uint32_t& auth_diagnostic)=0;
|
||||
/**
|
||||
* This function parse X509 certificate from the file and return some
|
||||
* verified informations, like ID and signer
|
||||
* @return false on error, true otherwise
|
||||
*/
|
||||
virtual bool parseX509DetailsFromFile(
|
||||
const std::string& certFilePath, RsPeerId& certId, RsPgpId& issuer,
|
||||
std::string& location ) = 0;
|
||||
|
||||
virtual ~AuthSSL();
|
||||
|
||||
virtual int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) = 0;
|
||||
virtual bool ValidateCertificate(X509 *x509, RsPeerId& peerId) = 0; /* validate + get id */
|
||||
protected:
|
||||
AuthSSL() {}
|
||||
|
||||
public: /* SSL specific functions used in pqissl/pqissllistener */
|
||||
virtual SSL_CTX *getCTX() = 0;
|
||||
|
||||
/* Restored these functions: */
|
||||
virtual void setCurrentConnectionAttemptInfo(const RsPgpId& gpg_id,const RsPeerId& ssl_id,const std::string& ssl_cn) = 0 ;
|
||||
virtual void getCurrentConnectionAttemptInfo( RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn) = 0 ;
|
||||
|
||||
virtual bool FailedCertificate(X509 *x509, const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming) = 0; /* store for discovery */
|
||||
virtual bool CheckCertificate(const RsPeerId& peerId, X509 *x509) = 0; /* check that they are exact match */
|
||||
|
||||
static void setAuthSSL_debug(AuthSSL*) ; // used for debug only. The real function is InitSSL()
|
||||
static AuthSSL *instance_ssl ;
|
||||
RS_SET_CONTEXT_DEBUG_LEVEL(2)
|
||||
};
|
||||
|
||||
|
||||
class AuthSSLimpl : public AuthSSL, public p3Config
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
/* Initialisation Functions (Unique) */
|
||||
/** Initialisation Functions (Unique) */
|
||||
AuthSSLimpl();
|
||||
bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey);
|
||||
bool validateOwnCertificate(X509 *x509, EVP_PKEY *pkey) override;
|
||||
|
||||
virtual bool active();
|
||||
virtual int InitAuth(const char *srvr_cert, const char *priv_key,
|
||||
const char *passwd, std::string alternative_location_name);
|
||||
virtual bool CloseAuth();
|
||||
bool active() override;
|
||||
int InitAuth( const char *srvr_cert, const char *priv_key,
|
||||
const char *passwd, std::string alternative_location_name )
|
||||
override;
|
||||
|
||||
bool CloseAuth() override;
|
||||
|
||||
/*********** Overloaded Functions from p3AuthMgr **********/
|
||||
|
||||
/* get Certificate Id */
|
||||
virtual const RsPeerId& OwnId();
|
||||
virtual std::string getOwnLocation();
|
||||
|
||||
const RsPeerId& OwnId() override;
|
||||
virtual std::string getOwnLocation() override;
|
||||
|
||||
/* Load/Save certificates */
|
||||
virtual std::string SaveOwnCertificateToString();
|
||||
|
||||
virtual std::string SaveOwnCertificateToString() override;
|
||||
|
||||
/* Sign / Encrypt / Verify Data */
|
||||
virtual bool SignData(std::string input, std::string &sign);
|
||||
virtual bool SignData(const void *data, const uint32_t len, std::string &sign);
|
||||
bool SignData(std::string input, std::string &sign) override;
|
||||
bool SignData(
|
||||
const void *data, const uint32_t len, std::string &sign) override;
|
||||
|
||||
virtual bool SignDataBin(std::string, unsigned char*, unsigned int*);
|
||||
virtual bool SignDataBin(const void*, uint32_t, unsigned char*, unsigned int*);
|
||||
virtual bool VerifyOwnSignBin(const void*, uint32_t, unsigned char*, unsigned int);
|
||||
virtual bool VerifySignBin(const void *data, const uint32_t len,
|
||||
unsigned char *sign, unsigned int signlen, const RsPeerId& sslId);
|
||||
bool SignDataBin(std::string, unsigned char*, unsigned int*) override;
|
||||
virtual bool SignDataBin(
|
||||
const void*, uint32_t, unsigned char*, unsigned int*) override;
|
||||
bool VerifyOwnSignBin(
|
||||
const void*, uint32_t, unsigned char*, unsigned int) override;
|
||||
virtual bool VerifySignBin(
|
||||
const void *data, const uint32_t len, unsigned char *sign,
|
||||
unsigned int signlen, const RsPeerId& sslId) override;
|
||||
|
||||
// return : false if encrypt failed
|
||||
virtual bool encrypt(void *&out, int &outlen, const void *in, int inlen, const RsPeerId& peerId);
|
||||
// return : false if decrypt fails
|
||||
virtual bool decrypt(void *&out, int &outlen, const void *in, int inlen);
|
||||
bool encrypt(
|
||||
void*& out, int& outlen, const void* in, int inlen,
|
||||
const RsPeerId& peerId ) override;
|
||||
bool decrypt(void *&out, int &outlen, const void *in, int inlen) override;
|
||||
|
||||
virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days) override;
|
||||
|
||||
virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days);
|
||||
virtual bool AuthX509WithGPG(X509 *x509,uint32_t& auth_diagnostic);
|
||||
/// @see AuthSSL
|
||||
bool AuthX509WithGPG(X509 *x509, uint32_t& auth_diagnostic) override;
|
||||
|
||||
/// @see AuthSSL
|
||||
int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx) override;
|
||||
|
||||
virtual int VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx);
|
||||
virtual bool ValidateCertificate(X509 *x509, RsPeerId& peerId); /* validate + get id */
|
||||
/// @see AuthSSL
|
||||
bool parseX509DetailsFromFile(
|
||||
const std::string& certFilePath, RsPeerId& certId,
|
||||
RsPgpId& issuer, std::string& location ) override;
|
||||
|
||||
|
||||
/*****************************************************************/
|
||||
/*********************** 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);
|
||||
/* Key Functions to be overloaded for Full Configuration */
|
||||
RsSerialiser* setupSerialiser() override;
|
||||
bool saveList(bool &cleanup, std::list<RsItem *>& ) override;
|
||||
bool loadList(std::list<RsItem *>& load) override;
|
||||
/*****************************************************************/
|
||||
|
||||
public: /* SSL specific functions used in pqissl/pqissllistener */
|
||||
virtual SSL_CTX *getCTX();
|
||||
public:
|
||||
/* SSL specific functions used in pqissl/pqissllistener */
|
||||
SSL_CTX* getCTX() override;
|
||||
|
||||
/* Restored these functions: */
|
||||
virtual void setCurrentConnectionAttemptInfo(const RsPgpId& gpg_id,const RsPeerId& ssl_id,const std::string& ssl_cn) ;
|
||||
virtual void getCurrentConnectionAttemptInfo( RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn) ;
|
||||
virtual bool FailedCertificate(X509 *x509, const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming); /* store for discovery */
|
||||
virtual bool CheckCertificate(const RsPeerId& peerId, X509 *x509); /* check that they are exact match */
|
||||
/* Restored these functions: */
|
||||
void setCurrentConnectionAttemptInfo(
|
||||
const RsPgpId& gpg_id, const RsPeerId& ssl_id,
|
||||
const std::string& ssl_cn ) override;
|
||||
void getCurrentConnectionAttemptInfo(
|
||||
RsPgpId& gpg_id, RsPeerId& ssl_id, std::string& ssl_cn ) override;
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
bool LocalStoreCert(X509* x509);
|
||||
bool RemoveX509(const RsPeerId id);
|
||||
bool LocalStoreCert(X509* x509);
|
||||
bool RemoveX509(const RsPeerId id);
|
||||
|
||||
/*********** LOCKED Functions ******/
|
||||
bool locked_FindCert(const RsPeerId& id, sslcert **cert);
|
||||
bool locked_FindCert(const RsPeerId& id, X509** cert);
|
||||
|
||||
/* Data */
|
||||
/* these variables are constants -> don't need to protect */
|
||||
SSL_CTX *sslctx;
|
||||
RsPeerId mOwnId;
|
||||
sslcert *mOwnCert;
|
||||
X509* mOwnCert;
|
||||
|
||||
RsMutex sslMtx; /* protects all below */
|
||||
RsMutex sslMtx; /* protects all below */
|
||||
|
||||
|
||||
EVP_PKEY *mOwnPrivateKey;
|
||||
EVP_PKEY *mOwnPublicKey;
|
||||
EVP_PKEY* mOwnPrivateKey;
|
||||
EVP_PKEY* mOwnPublicKey;
|
||||
|
||||
int init;
|
||||
std::map<RsPeerId, X509*> mCerts;
|
||||
|
||||
std::map<RsPeerId, sslcert *> mCerts;
|
||||
|
||||
RsPgpId _last_gpgid_to_connect ;
|
||||
std::string _last_sslcn_to_connect ;
|
||||
RsPeerId _last_sslid_to_connect ;
|
||||
RsPgpId _last_gpgid_to_connect;
|
||||
std::string _last_sslcn_to_connect;
|
||||
RsPeerId _last_sslid_to_connect;
|
||||
};
|
||||
|
||||
#endif // MRK_AUTH_SSL_HEADER
|
||||
|
@ -1038,47 +1038,6 @@ bool p3LinkMgrIMPL::connectResult(const RsPeerId &id, bool success, bool isIncom
|
||||
* From various sources
|
||||
*/
|
||||
|
||||
// from pqissl, when a connection failed due to security
|
||||
void p3LinkMgrIMPL::notifyDeniedConnection(const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &/*addr*/, bool incoming)
|
||||
{
|
||||
std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection()";
|
||||
std::cerr << " pgpid: " << gpgid;
|
||||
std::cerr << " sslid: " << sslid;
|
||||
std::cerr << " sslcn: " << sslcn;
|
||||
std::cerr << std::endl;
|
||||
|
||||
RsStackMutex stack(mLinkMtx); /****** STACK LOCK MUTEX *******/
|
||||
|
||||
std::map<RsPeerId, peerConnectState>::iterator it;
|
||||
it = mFriendList.find(sslid);
|
||||
if (it == mFriendList.end())
|
||||
{
|
||||
std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection() of NON-FRIEND: " << sslid;
|
||||
std::cerr << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.wasDeniedConnection = true;
|
||||
it->second.deniedTS = time(NULL);
|
||||
|
||||
if ((!incoming) && it->second.inConnAttempt)
|
||||
{
|
||||
it->second.deniedInConnAttempt = true;
|
||||
it->second.deniedConnectionAttempt = it->second.currentConnAddrAttempt;
|
||||
|
||||
std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection() Denied In Connection Attempt";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.deniedInConnAttempt = false;
|
||||
std::cerr << "p3LinkMgrIMPL::notifyDeniedConnection() Denied NOT In Connection Attempt";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void p3LinkMgrIMPL::peerStatus(const RsPeerId& id, const pqiIpAddrSet &addrs,
|
||||
uint32_t type, uint32_t flags, uint32_t source)
|
||||
{
|
||||
|
@ -171,8 +171,6 @@ virtual bool connectAttempt(const RsPeerId &id, struct sockaddr_storage &raddr,
|
||||
virtual bool connectResult(const RsPeerId &id, bool success, bool isIncomingConnection, uint32_t flags, const struct sockaddr_storage &remote_peer_address) = 0;
|
||||
virtual bool retryConnect(const RsPeerId &id) = 0;
|
||||
|
||||
virtual void notifyDeniedConnection(const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming) = 0;
|
||||
|
||||
/* Network Addresses */
|
||||
virtual bool setLocalAddress(const struct sockaddr_storage &addr) = 0;
|
||||
virtual bool getLocalAddress(struct sockaddr_storage &addr) = 0;
|
||||
@ -230,8 +228,6 @@ virtual bool connectAttempt(const RsPeerId &id, struct sockaddr_storage &raddr,
|
||||
virtual bool connectResult(const RsPeerId &id, bool success, bool isIncomingConnection, uint32_t flags, const struct sockaddr_storage &remote_peer_address);
|
||||
virtual bool retryConnect(const RsPeerId &id);
|
||||
|
||||
virtual void notifyDeniedConnection(const RsPgpId& gpgid,const RsPeerId& sslid,const std::string& sslcn,const struct sockaddr_storage &addr, bool incoming);
|
||||
|
||||
/* Network Addresses */
|
||||
virtual bool setLocalAddress(const struct sockaddr_storage &addr);
|
||||
virtual bool getLocalAddress(struct sockaddr_storage &addr);
|
||||
|
@ -1115,9 +1115,6 @@ int pqissl::SSL_Connection_Complete()
|
||||
|
||||
rslog(RSL_WARNING, pqisslzone, out);
|
||||
|
||||
// attempt real error.
|
||||
Extract_Failed_SSL_Certificate();
|
||||
|
||||
rslog(RSL_ALERT, pqisslzone, "pqissl::SSL_Connection_Complete() -> calling reset()");
|
||||
reset_locked();
|
||||
waiting = WAITING_FAIL_INTERFACE;
|
||||
@ -1132,159 +1129,93 @@ int pqissl::SSL_Connection_Complete()
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pqissl::Extract_Failed_SSL_Certificate()
|
||||
{
|
||||
std::cerr << "pqissl::Extract_Failed_SSL_Certificate() FAILED Connection due to Security Issues";
|
||||
std::cerr << std::endl;
|
||||
|
||||
#ifdef PQISSL_LOG_DEBUG
|
||||
rslog(RSL_DEBUG_BASIC, pqisslzone,
|
||||
"pqissl::Extract_Failed_SSL_Certificate()");
|
||||
#endif
|
||||
|
||||
// Get the Peer Certificate....
|
||||
X509 *peercert = SSL_get_peer_certificate(ssl_connection);
|
||||
|
||||
if (peercert == NULL)
|
||||
{
|
||||
rslog(RSL_WARNING, pqisslzone,
|
||||
"pqissl::Extract_Failed_SSL_Certificate() Peer Didnt Give Cert");
|
||||
|
||||
std::cerr << "pqissl::Extract_Failed_SSL_Certificate() ERROR Peer Didn't Give Us Certificate";
|
||||
std::cerr << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef PQISSL_LOG_DEBUG
|
||||
rslog(RSL_DEBUG_BASIC, pqisslzone,
|
||||
"pqissl::Extract_Failed_SSL_Certificate() Have Peer Cert - Registering");
|
||||
#endif
|
||||
|
||||
std::cerr << "pqissl::Extract_Failed_SSL_Certificate() Passing FAILED Cert to AuthSSL for analysis";
|
||||
std::cerr << std::endl;
|
||||
|
||||
// save certificate... (and ip locations)
|
||||
// false for outgoing....
|
||||
// we actually connected to remote_addr,
|
||||
// which could be
|
||||
// (pqissl's case) sslcert->serveraddr or sslcert->localaddr.
|
||||
|
||||
RsPeerId sslid ;
|
||||
getX509id(peercert, sslid) ;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
RsPgpId gpgid(getX509CNString(peercert->cert_info->issuer));
|
||||
std::string sslcn = getX509CNString(peercert->cert_info->subject);
|
||||
#else
|
||||
RsPgpId gpgid(getX509CNString(X509_get_issuer_name(peercert)));
|
||||
std::string sslcn = getX509CNString(X509_get_subject_name(peercert));
|
||||
#endif
|
||||
|
||||
AuthSSL::getAuthSSL()->FailedCertificate(peercert, gpgid,sslid,sslcn,remote_addr, false);
|
||||
mLinkMgr->notifyDeniedConnection(gpgid, sslid, sslcn, remote_addr, false);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int pqissl::Authorise_SSL_Connection()
|
||||
{
|
||||
#ifdef PQISSL_DEBUG
|
||||
std::cerr << __PRETTY_FUNCTION__ << std::endl;
|
||||
#endif
|
||||
Dbg3() << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
if (time(NULL) > ssl_connect_timeout)
|
||||
constexpr int failure = -1;
|
||||
|
||||
if (time(nullptr) > ssl_connect_timeout)
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Connection timed out reset!"
|
||||
<< std::endl;
|
||||
RsInfo() << __PRETTY_FUNCTION__ << " Connection timed out reset!"
|
||||
<< std::endl;
|
||||
reset_locked();
|
||||
}
|
||||
|
||||
int err;
|
||||
if (0 >= (err = SSL_Connection_Complete())) return err;
|
||||
|
||||
#ifdef PQISSL_LOG_DEBUG
|
||||
rslog(RSL_DEBUG_BASIC, pqisslzone,
|
||||
"pqissl::Authorise_SSL_Connection() SSL_Connection_Complete");
|
||||
#endif
|
||||
Dbg3() << __PRETTY_FUNCTION__ << "SSL_Connection_Complete success."
|
||||
<< std::endl;
|
||||
|
||||
// reset switch.
|
||||
waiting = WAITING_NOT;
|
||||
|
||||
X509 *peercert = SSL_get_peer_certificate(ssl_connection);
|
||||
|
||||
if (peercert == NULL)
|
||||
#ifdef RS_PQISSL_AUTH_DOUBLE_CHECK
|
||||
X509* peercert = SSL_get_peer_certificate(ssl_connection);
|
||||
if (!peercert)
|
||||
{
|
||||
rslog(RSL_WARNING, pqisslzone,
|
||||
"pqissl::Authorise_SSL_Connection() Peer Didnt Give Cert");
|
||||
|
||||
rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()");
|
||||
// Failed completely
|
||||
reset_locked();
|
||||
return -1;
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " failed to retrieve peer "
|
||||
<< "certificate at this point this should never happen!"
|
||||
<< std::endl;
|
||||
print_stacktrace();
|
||||
exit(failure);
|
||||
}
|
||||
|
||||
RsPeerId certPeerId;
|
||||
getX509id(peercert, certPeerId);
|
||||
if (RsPeerId(certPeerId) != PeerId()) {
|
||||
rslog(RSL_WARNING, pqisslzone,
|
||||
"pqissl::Authorise_SSL_Connection() the cert Id doesn't match the Peer id we're trying to connect to.");
|
||||
|
||||
rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()");
|
||||
// Failed completely
|
||||
reset_locked();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef PQISSL_LOG_DEBUG
|
||||
rslog(RSL_DEBUG_BASIC, pqisslzone,
|
||||
"pqissl::Authorise_SSL_Connection() Have Peer Cert");
|
||||
#endif
|
||||
|
||||
// save certificate... (and ip locations)
|
||||
// false for outgoing....
|
||||
// we actually connected to remote_addr,
|
||||
// which could be
|
||||
// (pqissl's case) sslcert->serveraddr or sslcert->localaddr.
|
||||
|
||||
AuthSSL::getAuthSSL()->CheckCertificate(PeerId(), peercert);
|
||||
bool certCorrect = true; /* WE know it okay already! */
|
||||
|
||||
uint32_t check_result ;
|
||||
uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST;
|
||||
if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL)
|
||||
checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST;
|
||||
|
||||
if(rsBanList!=NULL && !rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result))
|
||||
{
|
||||
std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " <<
|
||||
((check_result == RSBANLIST_CHECK_RESULT_NOT_WHITELISTED)?"not whitelisted (peer requires whitelist)":"blacklisted") << std::endl;
|
||||
|
||||
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(remote_addr), "", "", check_result);
|
||||
reset_locked();
|
||||
return 0 ;
|
||||
}
|
||||
// check it's the right one.
|
||||
if (certCorrect)
|
||||
RsPeerId certPeerId = RsX509Cert::getCertSslId(*peercert);
|
||||
if (RsPeerId(certPeerId) != PeerId())
|
||||
{
|
||||
// then okay...
|
||||
rslog(RSL_WARNING, pqisslzone, "pqissl::Authorise_SSL_Connection() Accepting Conn. Peer: " + PeerId().toStdString());
|
||||
RsErr() << __PRETTY_FUNCTION__ << " the cert Id doesn't match the peer "
|
||||
<< "id we're trying to connect to." << std::endl;
|
||||
|
||||
//std::cerr << "pqissl::Authorise_SSL_Connection(): accepting connection from " << sockaddr_storage_iptostring(remote_addr) << std::endl;
|
||||
accept_locked(ssl_connection, sockfd, remote_addr);
|
||||
return 1;
|
||||
/* TODO: Considering how difficult is managing to get a connection to a
|
||||
* friend nowadays on the Internet because of evil NAT everywhere.
|
||||
* If the cert is from a friend anyway we should find a way to make good
|
||||
* use of this connection instead of throwing it away... */
|
||||
|
||||
X509_free(peercert);
|
||||
reset_locked();
|
||||
return failure;
|
||||
}
|
||||
|
||||
rslog(RSL_WARNING, pqisslzone, "pqissl::Authorise_SSL_Connection() Something Wrong ... Shutdown. Peer: " + PeerId().toStdString());
|
||||
/* At this point the actual connection authentication has already been
|
||||
* performed in AuthSSL::VerifyX509Callback, any furter authentication check
|
||||
* like the following two are redundant. */
|
||||
|
||||
// else shutdown ssl connection.
|
||||
rslog(RSL_ALERT, pqisslzone, "pqissl::Authorise_Connection_Complete() -> calling reset()");
|
||||
uint32_t authErrCode = 0;
|
||||
if(!AuthSSL::instance().AuthX509WithGPG(peercert, authErrCode))
|
||||
{
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " failure verifying peer "
|
||||
<< "certificate signature. This should never happen at this "
|
||||
<< "point!" << std::endl;
|
||||
print_stacktrace();
|
||||
|
||||
reset_locked();
|
||||
return 0;
|
||||
X509_free(peercert); // not needed but just in case we change to return
|
||||
exit(failure);
|
||||
}
|
||||
|
||||
RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert);
|
||||
if( pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() &&
|
||||
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
|
||||
{
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
|
||||
<< " is not friend. It is very unlikely to happen at this "
|
||||
<< "point! Either the user must have been so fast to deny "
|
||||
<< "friendship just after VerifyX509Callback have returned "
|
||||
<< "success and just before this code being executed, or "
|
||||
<< "something really fishy is happening! Share the full log "
|
||||
<< "with developers." << std::endl;
|
||||
print_stacktrace();
|
||||
|
||||
X509_free(peercert); // not needed but just in case we change to return
|
||||
exit(failure);
|
||||
}
|
||||
#endif // def RS_PQISSL_AUTH_REDUNDANT_CHECK
|
||||
|
||||
Dbg2() << __PRETTY_FUNCTION__ << " Accepting connection to peer: "
|
||||
<< PeerId() << " with address: " << remote_addr << std::endl;
|
||||
|
||||
return accept_locked(ssl_connection, sockfd, remote_addr);
|
||||
}
|
||||
|
||||
|
||||
@ -1300,13 +1231,20 @@ int pqissl::accept( SSL *ssl, int fd,
|
||||
return accept_locked(ssl, fd, foreign_addr);
|
||||
}
|
||||
|
||||
int pqissl::accept_locked( SSL *ssl, int fd,
|
||||
int pqissl::accept_locked( SSL *ssl, int fd,
|
||||
const sockaddr_storage &foreign_addr )
|
||||
{
|
||||
#ifdef PQISSL_DEBUG
|
||||
std::cerr << __PRETTY_FUNCTION__ << std::endl;
|
||||
#endif
|
||||
Dbg3() << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
constexpr int failure = -1;
|
||||
constexpr int success = 1;
|
||||
|
||||
#ifdef RS_PQISSL_BANLIST_DOUBLE_CHECK
|
||||
/* At this point, as we are actively attempting the connection, we decide
|
||||
* the address to which to connect to, banned addresses should never get
|
||||
* here as the filtering for banned addresses happens much before, this
|
||||
* check is therefore redundant, and if it trigger something really fishy
|
||||
* must be happening (a bug somewhere else in the code). */
|
||||
uint32_t check_result;
|
||||
uint32_t checking_flags = RSBANLIST_CHECKING_FLAGS_BLACKLIST;
|
||||
|
||||
@ -1317,11 +1255,13 @@ int pqissl::accept_locked( SSL *ssl, int fd,
|
||||
checking_flags,
|
||||
&check_result ) )
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__
|
||||
<< " (SS) refusing incoming SSL connection from blacklisted "
|
||||
<< "foreign address "
|
||||
<< sockaddr_storage_iptostring(foreign_addr)
|
||||
<< ". Reason: " << check_result << "." << std::endl;
|
||||
RsErr() << __PRETTY_FUNCTION__
|
||||
<< " Refusing incoming SSL connection from blacklisted "
|
||||
<< "foreign address " << foreign_addr
|
||||
<< ". Reason: " << check_result << ". This should never happen "
|
||||
<< "at this point! Please report full log to developers!"
|
||||
<< std::endl;
|
||||
print_stacktrace();
|
||||
|
||||
RsServer::notify()->AddFeedItem(
|
||||
RS_FEED_ITEM_SEC_IP_BLACKLISTED,
|
||||
@ -1329,14 +1269,15 @@ int pqissl::accept_locked( SSL *ssl, int fd,
|
||||
sockaddr_storage_iptostring(foreign_addr), "", "",
|
||||
check_result);
|
||||
reset_locked();
|
||||
return -1;
|
||||
return failure;
|
||||
}
|
||||
#endif //def RS_BANLIST_REDUNDANT_CHECK
|
||||
|
||||
if (waiting != WAITING_NOT)
|
||||
{
|
||||
std::cerr << __PRETTY_FUNCTION__ << " Peer: " << PeerId().toStdString()
|
||||
<< " - Two connections in progress - Shut 1 down!"
|
||||
<< std::endl;
|
||||
RsInfo() << __PRETTY_FUNCTION__ << " Peer: " << PeerId()
|
||||
<< " - Two connections in progress - Shut 1 down!"
|
||||
<< std::endl;
|
||||
|
||||
// outgoing connection in progress.
|
||||
// shut this baby down.
|
||||
@ -1431,7 +1372,7 @@ int pqissl::accept_locked( SSL *ssl, int fd,
|
||||
waiting = WAITING_FAIL_INTERFACE; // failed completely.
|
||||
|
||||
reset_locked();
|
||||
return -1;
|
||||
return failure;
|
||||
}
|
||||
#ifdef PQISSL_DEBUG
|
||||
else std::cerr << __PRETTY_FUNCTION__ << " Socket made non-nlocking!"
|
||||
@ -1456,7 +1397,7 @@ int pqissl::accept_locked( SSL *ssl, int fd,
|
||||
sockaddr_storage addr; sockaddr_storage_copy(remote_addr, addr);
|
||||
parent()->notifyEvent(this, NET_CONNECT_SUCCESS, addr);
|
||||
}
|
||||
return 1;
|
||||
return success;
|
||||
}
|
||||
|
||||
/********** Implementation of BinInterface **************************
|
||||
|
@ -3,8 +3,8 @@
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
* *
|
||||
* Copyright 2004-2006 by Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* Copyright (C) 2004-2006 Robert Fernie <retroshare@lunamutt.com> *
|
||||
* Copyright (C) 2015-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License as *
|
||||
@ -20,8 +20,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifndef MRK_PQI_SSL_HEADER
|
||||
#define MRK_PQI_SSL_HEADER
|
||||
#pragma once
|
||||
|
||||
// operating system specific network header.
|
||||
#include "pqi/pqinetwork.h"
|
||||
@ -32,6 +31,11 @@
|
||||
#include "pqi/pqi_base.h"
|
||||
#include "pqi/authssl.h"
|
||||
|
||||
#define RS_PQISSL_AUTH_DOUBLE_CHECK 1
|
||||
|
||||
#define RS_PQISSL_BANLIST_DOUBLE_CHECK 1
|
||||
|
||||
|
||||
#define WAITING_NOT 0
|
||||
#define WAITING_DELAY 1
|
||||
#define WAITING_SOCK_CONNECT 2
|
||||
@ -159,8 +163,6 @@ int Initiate_SSL_Connection();
|
||||
int SSL_Connection_Complete();
|
||||
int Authorise_SSL_Connection();
|
||||
|
||||
int Extract_Failed_SSL_Certificate(); // try to get cert anyway.
|
||||
|
||||
// check connection timeout.
|
||||
bool CheckConnectionTimeout();
|
||||
|
||||
@ -207,9 +209,6 @@ bool CheckConnectionTimeout();
|
||||
private:
|
||||
// ssl only fns.
|
||||
int connectInterface(const struct sockaddr_storage &addr);
|
||||
|
||||
RS_SET_CONTEXT_DEBUG_LEVEL(1)
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // MRK_PQI_SSL_HEADER
|
||||
|
@ -20,20 +20,20 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include "pqi/pqissl.h"
|
||||
#include "pqi/pqissllistener.h"
|
||||
#include "pqi/pqinetwork.h"
|
||||
#include "pqi/sslfns.h"
|
||||
|
||||
#include "pqi/p3peermgr.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "retroshare/rsbanlist.h"
|
||||
#include "pqi/authgpg.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
static struct RsLog::logInfo pqissllistenzoneInfo = {RsLog::Default, "p3peermgr"};
|
||||
#define pqissllistenzone &pqissllistenzoneInfo
|
||||
@ -486,9 +486,6 @@ int pqissllistenbase::continueSSL(IncomingSSLInfo& incoming_connexion_info, bool
|
||||
break;
|
||||
}
|
||||
|
||||
/* we have failed -> get certificate if possible */
|
||||
Extract_Failed_SSL_Certificate(incoming_connexion_info);
|
||||
|
||||
closeConnection(fd, incoming_connexion_info.ssl) ;
|
||||
|
||||
pqioutput(PQL_WARNING, pqissllistenzone, "Read Error on the SSL Socket\nShutting it down!");
|
||||
@ -502,20 +499,11 @@ int pqissllistenbase::continueSSL(IncomingSSLInfo& incoming_connexion_info, bool
|
||||
//
|
||||
X509 *x509 = SSL_get_peer_certificate(incoming_connexion_info.ssl) ;
|
||||
|
||||
#ifdef DEBUG_LISTENNER
|
||||
std::cerr << "Info from certificate: " << std::endl;
|
||||
#endif
|
||||
if(x509 != NULL)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
incoming_connexion_info.gpgid = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer)));
|
||||
incoming_connexion_info.sslcn = getX509CNString(x509->cert_info->subject);
|
||||
#else
|
||||
incoming_connexion_info.gpgid = RsPgpId(std::string(getX509CNString(X509_get_issuer_name(x509))));
|
||||
incoming_connexion_info.sslcn = getX509CNString(X509_get_subject_name(x509));
|
||||
#endif
|
||||
|
||||
getX509id(x509,incoming_connexion_info.sslid);
|
||||
if(x509)
|
||||
{
|
||||
incoming_connexion_info.gpgid = RsX509Cert::getCertIssuer(*x509);
|
||||
incoming_connexion_info.sslcn = RsX509Cert::getCertName(*x509);
|
||||
incoming_connexion_info.sslid = RsX509Cert::getCertSslId(*x509);
|
||||
|
||||
#ifdef DEBUG_LISTENNER
|
||||
std::cerr << " Got PGP Id = " << incoming_connexion_info.gpgid << std::endl;
|
||||
@ -571,61 +559,6 @@ int pqissllistenbase::closeConnection(int fd, SSL *ssl)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int pqissllistenbase::Extract_Failed_SSL_Certificate(const IncomingSSLInfo& info)
|
||||
{
|
||||
pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, "pqissllistenbase::Extract_Failed_SSL_Certificate()");
|
||||
|
||||
std::cerr << "pqissllistenbase::Extract_Failed_SSL_Certificate() FAILED CONNECTION due to security!";
|
||||
std::cerr << std::endl;
|
||||
|
||||
// Get the Peer Certificate....
|
||||
X509 *peercert = SSL_get_peer_certificate(info.ssl);
|
||||
|
||||
std::cerr << "Extract_Failed_SSL_Certificate: " << std::endl;
|
||||
std::cerr << " SSL = " << (void*)info.ssl << std::endl;
|
||||
std::cerr << " GPG id = " << info.gpgid << std::endl;
|
||||
std::cerr << " SSL id = " << info.sslid << std::endl;
|
||||
std::cerr << " SSL cn = " << info.sslcn << std::endl;
|
||||
std::cerr << " addr+p = " << sockaddr_storage_tostring(info.addr) << std::endl;
|
||||
|
||||
if (peercert == NULL)
|
||||
{
|
||||
std::string out;
|
||||
out += "pqissllistenbase::Extract_Failed_SSL_Certificate() from: ";
|
||||
out += sockaddr_storage_tostring(info.addr);
|
||||
out += " ERROR Peer didn't give Cert!";
|
||||
std::cerr << out << std::endl;
|
||||
AuthSSL::getAuthSSL()->FailedCertificate(peercert, info.gpgid,info.sslid,info.sslcn,info.addr, true);
|
||||
|
||||
pqioutput(PQL_WARNING, pqissllistenzone, out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pqioutput(PQL_DEBUG_BASIC, pqissllistenzone,
|
||||
"pqissllistenbase::Extract_Failed_SSL_Certificate() Have Peer Cert - Registering");
|
||||
|
||||
{
|
||||
std::string out;
|
||||
out += "pqissllistenbase::Extract_Failed_SSL_Certificate() from: ";
|
||||
out += sockaddr_storage_tostring(info.addr);
|
||||
out += " Passing Cert to AuthSSL() for analysis";
|
||||
std::cerr << out << std::endl;
|
||||
|
||||
pqioutput(PQL_WARNING, pqissllistenzone, out);
|
||||
std::cerr << out << std::endl;
|
||||
}
|
||||
|
||||
// save certificate... (and ip locations)
|
||||
// false for outgoing....
|
||||
AuthSSL::getAuthSSL()->FailedCertificate(peercert, info.gpgid,info.sslid,info.sslcn,info.addr, true);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int pqissllistenbase::continueaccepts()
|
||||
{
|
||||
|
||||
@ -830,91 +763,73 @@ int pqissllistener::status()
|
||||
}
|
||||
|
||||
int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info)
|
||||
{
|
||||
{
|
||||
constexpr int failure = -1;
|
||||
constexpr int success = 1;
|
||||
|
||||
// Get the Peer Certificate....
|
||||
X509 *peercert = SSL_get_peer_certificate(info.ssl);
|
||||
|
||||
if (peercert == NULL)
|
||||
X509* peercert = SSL_get_peer_certificate(info.ssl);
|
||||
if(!peercert)
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqissllistenzone,
|
||||
"pqissllistener::completeConnection() Peer Did Not Provide Cert!");
|
||||
|
||||
// failure -1, pending 0, sucess 1.
|
||||
// pqissllistenbase will shutdown!
|
||||
return -1;
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " failed to retrieve peer "
|
||||
<< "certificate at this point this should never happen!"
|
||||
<< std::endl;
|
||||
print_stacktrace();
|
||||
exit(failure);
|
||||
}
|
||||
|
||||
// Check cert.
|
||||
RsPeerId newPeerId;
|
||||
RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert);
|
||||
RsPeerId newPeerId = RsX509Cert::getCertSslId(*peercert);
|
||||
|
||||
#ifdef RS_PQISSL_AUTH_DOUBLE_CHECK
|
||||
/* At this point the actual connection authentication has already been
|
||||
* performed in AuthSSL::VerifyX509Callback, any furter authentication check
|
||||
* like the following two are redundant. */
|
||||
|
||||
/****
|
||||
* As the validation is actually done before this...
|
||||
* we should only need to call CheckCertificate here!
|
||||
****/
|
||||
uint32_t authErrCode = 0;
|
||||
if(!AuthSSL::instance().AuthX509WithGPG(peercert, authErrCode))
|
||||
{
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " failure verifying peer "
|
||||
<< "certificate signature. This should never happen at this "
|
||||
<< "point!" << std::endl;
|
||||
print_stacktrace();
|
||||
|
||||
bool certOk = AuthSSL::getAuthSSL()->ValidateCertificate(peercert, newPeerId);
|
||||
X509_free(peercert); // not needed but just in case we change to return
|
||||
exit(failure);
|
||||
}
|
||||
|
||||
if( pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() &&
|
||||
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
|
||||
{
|
||||
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
|
||||
<< " is not friend. It is very unlikely to happen at this "
|
||||
<< "point! Either the user must have been so fast to deny "
|
||||
<< "friendship just after VerifyX509Callback have returned "
|
||||
<< "success and just before this code being executed, or "
|
||||
<< "something really fishy is happening! Share the full log "
|
||||
<< "with developers." << std::endl;
|
||||
print_stacktrace();
|
||||
|
||||
X509_free(peercert); // not needed but just in case we change to return
|
||||
exit(failure);
|
||||
}
|
||||
#endif //def RS_PQISSL_AUTH_REDUNDANT_CHECK
|
||||
|
||||
bool found = false;
|
||||
std::map<RsPeerId, pqissl *>::iterator it;
|
||||
|
||||
// Let connected one through as well! if ((npc == NULL) || (npc -> Connected()))
|
||||
if (!certOk)
|
||||
for(auto it = listenaddr.begin(); !found && it != listenaddr.end(); )
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqissllistenzone,
|
||||
"pqissllistener::completeConnection() registerCertificate Failed!");
|
||||
|
||||
// bad - shutdown.
|
||||
// pqissllistenbase will shutdown!
|
||||
X509_free(peercert);
|
||||
|
||||
return -1;
|
||||
if (it -> first == newPeerId) found = true;
|
||||
else ++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string out = "pqissllistener::continueSSL()\nchecking: " + newPeerId.toStdString() + "\n";
|
||||
// check if cert is in our list.....
|
||||
for(it = listenaddr.begin();(found!=true) && (it!=listenaddr.end());)
|
||||
{
|
||||
out + "\tagainst: " + it->first.toStdString() + "\n";
|
||||
if (it -> first == newPeerId)
|
||||
{
|
||||
// accept even if already connected.
|
||||
out += "\t\tMatch!";
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
pqioutput(PQL_DEBUG_BASIC, pqissllistenzone, out);
|
||||
}
|
||||
|
||||
if (found == false)
|
||||
{
|
||||
std::string out = "No Matching Certificate for Connection:";
|
||||
out += sockaddr_storage_tostring(info.addr);
|
||||
out += "\npqissllistenbase: Will shut it down!";
|
||||
pqioutput(PQL_WARNING, pqissllistenzone, out);
|
||||
Dbg1() << __PRETTY_FUNCTION__ << " got secure connection from address: "
|
||||
<< info.addr << " with previously unknown SSL certificate: "
|
||||
<< newPeerId << " signed by PGP friend: " << pgpId
|
||||
<< ". Adding the new location as SSL friend." << std::endl;
|
||||
|
||||
// but as it passed the authentication step,
|
||||
// we can add it into the AuthSSL, and mConnMgr.
|
||||
|
||||
AuthSSL::getAuthSSL()->CheckCertificate(newPeerId, peercert);
|
||||
|
||||
/* now need to get GPG id too */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
RsPgpId pgpid(std::string(getX509CNString(peercert->cert_info->issuer)));
|
||||
#else
|
||||
RsPgpId pgpid(std::string(getX509CNString(X509_get_issuer_name(peercert))));
|
||||
#endif
|
||||
mPeerMgr->addFriend(newPeerId, pgpid);
|
||||
|
||||
X509_free(peercert);
|
||||
return -1;
|
||||
mPeerMgr->addFriend(newPeerId, pgpId);
|
||||
}
|
||||
|
||||
// Cleanup cert.
|
||||
@ -926,17 +841,14 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info)
|
||||
as.mSSL = info.ssl;
|
||||
as.mPeerId = newPeerId;
|
||||
as.mAddr = info.addr;
|
||||
as.mAcceptTS = time(NULL);
|
||||
as.mAcceptTS = time(nullptr);
|
||||
|
||||
accepted_ssl.push_back(as);
|
||||
|
||||
std::string out = "pqissllistener::completeConnection() Successful Connection with: " + newPeerId.toStdString();
|
||||
out += " for Connection:";
|
||||
out += sockaddr_storage_tostring(info.addr);
|
||||
out += " Adding to WAIT-ACCEPT Queue";
|
||||
pqioutput(PQL_WARNING, pqissllistenzone, out);
|
||||
Dbg1() << __PRETTY_FUNCTION__ << "Successful Connection with: "
|
||||
<< newPeerId << " with address: " << info.addr << std::endl;
|
||||
|
||||
return 1;
|
||||
return success;
|
||||
}
|
||||
|
||||
int pqissllistener::finaliseConnection(int fd, SSL *ssl, const RsPeerId& peerId, const struct sockaddr_storage &remote_addr)
|
||||
|
@ -19,21 +19,20 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifndef MRK_PQI_SSL_LISTEN_HEADER
|
||||
#define MRK_PQI_SSL_LISTEN_HEADER
|
||||
#pragma once
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
// operating system specific network header.
|
||||
#include "pqi/pqinetwork.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "pqi/pqi_base.h"
|
||||
#include "pqi/pqilistener.h"
|
||||
|
||||
#include "pqi/authssl.h"
|
||||
#include "util/rsdebug.h"
|
||||
#include "pqi/pqinetwork.h"
|
||||
|
||||
#define RS_PQISSL_AUTH_DOUBLE_CHECK 1
|
||||
|
||||
/***************************** pqi Net SSL Interface *********************************
|
||||
*/
|
||||
@ -98,7 +97,7 @@ protected:
|
||||
p3PeerMgr *mPeerMgr;
|
||||
|
||||
private:
|
||||
int Extract_Failed_SSL_Certificate(const IncomingSSLInfo&);
|
||||
|
||||
bool active;
|
||||
int lsock;
|
||||
std::list<IncomingSSLInfo> incoming_ssl ;
|
||||
@ -122,7 +121,6 @@ public:
|
||||
|
||||
private:
|
||||
std::map<RsPeerId, pqissl*> listenaddr;
|
||||
|
||||
RS_SET_CONTEXT_DEBUG_LEVEL(2)
|
||||
};
|
||||
|
||||
|
||||
#endif // MRK_PQI_SSL_LISTEN_HEADER
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "pqi/pqi_base.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "pqi/authssl.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
@ -675,13 +676,6 @@ int pem_passwd_cb(char *buf, int size, int rwflag, void *password)
|
||||
return(strlen(buf));
|
||||
}
|
||||
|
||||
/* XXX FIX */
|
||||
bool CheckX509Certificate(X509 */*x509*/)
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t getX509SerialNumber(X509 *cert)
|
||||
{
|
||||
ASN1_INTEGER *serial = X509_get_serialNumber(cert);
|
||||
@ -711,69 +705,6 @@ uint32_t getX509RetroshareCertificateVersion(X509 *cert)
|
||||
}
|
||||
}
|
||||
|
||||
// Not dependent on sslroot. load, and detroys the X509 memory.
|
||||
int LoadCheckX509(const char *cert_file, RsPgpId& issuerName, std::string &location, RsPeerId &userId)
|
||||
{
|
||||
/* This function loads the X509 certificate from the file,
|
||||
* and checks the certificate
|
||||
*/
|
||||
|
||||
FILE *tmpfp = RsDirUtil::rs_fopen(cert_file, "r");
|
||||
if (tmpfp == NULL)
|
||||
{
|
||||
#ifdef AUTHSSL_DEBUG
|
||||
std::cerr << "sslroot::LoadCheckAndGetX509Name()";
|
||||
std::cerr << " Failed to open Certificate File:" << cert_file;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get xPGP certificate.
|
||||
X509 *x509 = PEM_read_X509(tmpfp, NULL, NULL, NULL);
|
||||
fclose(tmpfp);
|
||||
|
||||
// check the certificate.
|
||||
bool valid = false;
|
||||
if (x509)
|
||||
{
|
||||
valid = CheckX509Certificate(x509);
|
||||
if (valid)
|
||||
{
|
||||
valid = getX509id(x509, userId);
|
||||
}
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{
|
||||
// extract the name.
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
issuerName = RsPgpId(std::string(getX509CNString(x509->cert_info->issuer)));
|
||||
location = getX509LocString(x509->cert_info->subject);
|
||||
#else
|
||||
issuerName = RsPgpId(std::string(getX509CNString(X509_get_issuer_name(x509))));
|
||||
location = getX509LocString(X509_get_subject_name(x509));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef AUTHSSL_DEBUG
|
||||
std::cout << getX509Info(x509) << std::endl ;
|
||||
#endif
|
||||
// clean up.
|
||||
X509_free(x509);
|
||||
|
||||
if (valid)
|
||||
{
|
||||
// happy!
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// something went wrong!
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getX509NameString(X509_NAME *name)
|
||||
{
|
||||
std::string namestr;
|
||||
@ -896,10 +827,9 @@ std::string getX509Info(X509 *cert)
|
||||
|
||||
/********** SSL ERROR STUFF ******************************************/
|
||||
|
||||
int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string &out)
|
||||
int printSSLError(
|
||||
SSL*, int retval, int err, unsigned long err2, std::string& out )
|
||||
{
|
||||
(void) ssl; /* remove unused parameter warnings */
|
||||
|
||||
std::string reason;
|
||||
|
||||
std::string mainreason = std::string("UNKNOWN ERROR CODE");
|
||||
@ -939,7 +869,18 @@ int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string
|
||||
{
|
||||
mainreason = std::string("SSL_ERROR_SSL");
|
||||
}
|
||||
rs_sprintf_append(out, "RetVal(%d) -> SSL Error: %s\n\t + ERR Error: %s\n", retval, mainreason.c_str(), ERR_error_string(err2, NULL));
|
||||
rs_sprintf_append( out,
|
||||
"RetVal(%d) -> SSL Error: %s\n\t + ERR Error: %s\n",
|
||||
retval, mainreason.c_str(),
|
||||
ERR_error_string(err2, nullptr) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
std::string sslErrorToString(int retval, int err, unsigned long err2)
|
||||
{
|
||||
std::string ret;
|
||||
// When printSSLError will be removed it's code will be moved here
|
||||
printSSLError(nullptr, retval, err, err2, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*******************************************************************************
|
||||
/*******************************************************************************
|
||||
* libretroshare/src/pqi: sslfns.h *
|
||||
* *
|
||||
* libretroshare: retroshare core library *
|
||||
@ -19,8 +19,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
#ifndef RS_PQI_SSL_HELPER_H
|
||||
#define RS_PQI_SSL_HELPER_H
|
||||
#pragma once
|
||||
|
||||
/* Functions in this file are SSL only,
|
||||
* and have no dependence on SSLRoot() etc.
|
||||
@ -32,9 +31,12 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <retroshare/rstypes.h>
|
||||
#include <string>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "util/rsdeprecate.h"
|
||||
#include "retroshare/rstypes.h"
|
||||
|
||||
|
||||
/****
|
||||
* #define AUTHSSL_DEBUG 1
|
||||
@ -113,11 +115,6 @@ bool getX509id(X509 *x509, RsPeerId &xid);
|
||||
|
||||
int pem_passwd_cb(char *buf, int size, int rwflag, void *password);
|
||||
|
||||
bool CheckX509Certificate(X509 *x509);
|
||||
// Not dependent on sslroot. load, and detroys the X509 memory.
|
||||
int LoadCheckX509(const char *cert_file, RsPgpId& issuer, std::string &location, RsPeerId& userId);
|
||||
|
||||
|
||||
std::string getX509NameString(X509_NAME *name);
|
||||
std::string getX509CNString(X509_NAME *name);
|
||||
std::string getX509TypeString(X509_NAME *name, const char *type, int len);
|
||||
@ -131,7 +128,8 @@ uint32_t getX509RetroshareCertificateVersion(X509 *cert) ;
|
||||
|
||||
/********** SSL ERROR STUFF ******************************************/
|
||||
|
||||
int printSSLError(SSL *ssl, int retval, int err, unsigned long err2, std::string &out);
|
||||
|
||||
#endif /* RS_PQI_SSL_HELPER_H */
|
||||
RS_DEPRECATED_FOR(sslErrorToString)
|
||||
int printSSLError(
|
||||
SSL* unused, int retval, int err, unsigned long err2, std::string& out);
|
||||
|
||||
std::string sslErrorToString(int retval, int err, unsigned long err2);
|
||||
|
@ -686,7 +686,8 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
|
||||
bool ret = false;
|
||||
|
||||
/* check against authmanagers private keys */
|
||||
if (LoadCheckX509(cert_name.c_str(), account.mPgpId, account.mLocation, account.mSslId))
|
||||
if(AuthSSL::instance().parseX509DetailsFromFile(
|
||||
cert_name, account.mSslId, account.mPgpId, account.mLocation ))
|
||||
{
|
||||
// new locations store the name in an extra file
|
||||
if(account.mLocation == "")
|
||||
@ -1117,8 +1118,11 @@ bool RsAccountsDetail::GenerateSSLCertificate(const RsPgpId& pgp_id, const s
|
||||
std::string location;
|
||||
RsPgpId pgpid_retrieved;
|
||||
|
||||
if (LoadCheckX509(cert_name.c_str(), pgpid_retrieved, location, sslId) == 0) {
|
||||
std::cerr << "RsInit::GenerateSSLCertificate() Cannot check own signature, maybe the files are corrupted." << std::endl;
|
||||
if(!AuthSSL::instance().parseX509DetailsFromFile(
|
||||
cert_name, sslId, pgpid_retrieved, location ))
|
||||
{
|
||||
RsErr() << __PRETTY_FUNCTION__ << " Cannot check own signature, maybe "
|
||||
<< "the files are corrupted." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -397,9 +397,8 @@ int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */)
|
||||
* 2) Get List of Available Accounts.
|
||||
* 4) Get List of GPG Accounts.
|
||||
*/
|
||||
/* create singletons */
|
||||
AuthSSL::AuthSSLInit();
|
||||
AuthSSL::getAuthSSL() -> InitAuth(NULL, NULL, NULL, "");
|
||||
/* Initialize AuthSSL */
|
||||
AuthSSL::instance().InitAuth(nullptr, nullptr, nullptr, "");
|
||||
|
||||
rsLoginHelper = new RsLoginHelper;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user