allow ssl connection with a new cert, ad a friend when happening

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@2014 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
joss17 2010-01-13 21:16:56 +00:00
parent bb45fa3db5
commit 485f27dc11
4 changed files with 139 additions and 18 deletions

View File

@ -33,6 +33,7 @@
#include "pqinetwork.h" #include "pqinetwork.h"
#include "authgpg.h" #include "authgpg.h"
#include "pqi/p3connmgr.h"
/******************** notify of new Cert **************************/ /******************** notify of new Cert **************************/
#include "pqinotify.h" #include "pqinotify.h"
@ -52,6 +53,10 @@
// initialisation du pointeur de singleton à zéro // initialisation du pointeur de singleton à zéro
AuthSSL *AuthSSL::instance_ssl = new AuthSSL(); AuthSSL *AuthSSL::instance_ssl = new AuthSSL();
// initialisation du pointeur de ex data du ssl context
int AuthSSL::ex_data_ctx_index = 0;
sslcert::sslcert(X509 *x509, std::string pid) sslcert::sslcert(X509 *x509, std::string pid)
{ {
certificate = x509; certificate = x509;
@ -587,6 +592,36 @@ SSL_CTX *AuthSSL::getCTX()
return sslctx; return sslctx;
} }
/* Context handling */
SSL_CTX *AuthSSL::getNewSslCtx()
{
#ifdef AUTHSSL_DEBUG
std::cerr << "AuthSSL::getNewSslCtx()";
std::cerr << std::endl;
#endif
// setup connection method
SSL_CTX *newSslctx = SSL_CTX_new(TLSv1_method());
// setup cipher lists.
SSL_CTX_set_cipher_list(newSslctx, "DEFAULT");
// certificates (Set Local Server Certificate).
SSL_CTX_use_certificate(newSslctx, mOwnCert->certificate);
// get private key
SSL_CTX_use_PrivateKey(newSslctx, pkey);
// enable verification of certificates (PEER)
// and install verify callback.
SSL_CTX_set_verify(newSslctx, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
verify_x509_callback);
std::cerr << "getNewSslCtx() finished" << std::endl;
return newSslctx;
}
int AuthSSL::setConfigDirectories(std::string configfile, std::string neighdir) int AuthSSL::setConfigDirectories(std::string configfile, std::string neighdir)
{ {
#ifdef AUTHSSL_DEBUG #ifdef AUTHSSL_DEBUG
@ -1880,13 +1915,37 @@ X509 *AuthSSL::SignX509Req(X509_REQ *req, long days)
bool AuthSSL::AuthX509(X509 *x509) bool AuthSSL::AuthX509(X509 *x509)
{ {
fprintf(stderr, "AuthSSL::AuthX509() called\n");
RsStackMutex stack(sslMtx); /******* LOCKED ******/ RsStackMutex stack(sslMtx); /******* LOCKED ******/
/* extract CN for peer Id */ /* extract CN for peer Id */
X509_NAME *issuer = X509_get_issuer_name(x509); std::string issuer = getX509CNString(x509->cert_info->issuer);
std::string id = ""; //check that the issuer is in the accepted GPG key list.
std::list<std::string> acceptedIds;
AuthGPG::getAuthGPG()->getPGPAcceptedList(acceptedIds);
bool isAccepted = false;
for(std::list<std::string>::iterator it = acceptedIds.begin(); it != acceptedIds.end(); it++){
std::cerr << "AuthSSL::AuthX509() : accepted id : " << *it << std::endl;
if (*it == issuer) {
isAccepted = true;
break;
}
}
if (!isAccepted) {
//check that the gpg key is not one of our private key usefull for initialisation
AuthGPG::getAuthGPG()->availablePGPCertificatesWithPrivateKeys(acceptedIds);
bool isAccepted = false;
for(std::list<std::string>::iterator it = acceptedIds.begin(); it != acceptedIds.end(); it++){
std::cerr << "AuthSSL::AuthX509() : accepted id : " << *it << std::endl;
if (*it == issuer) {
isAccepted = true;
break;
}
}
}
/* verify signature */ /* verify GPG signature */
/*** NOW The Manual signing bit (HACKED FROM asn1/a_sign.c) ***/ /*** NOW The Manual signing bit (HACKED FROM asn1/a_sign.c) ***/
int (*i2d)(X509_CINF*, unsigned char**) = i2d_X509_CINF; int (*i2d)(X509_CINF*, unsigned char**) = i2d_X509_CINF;
@ -2132,12 +2191,68 @@ int AuthSSL::VerifyX509Callback(int preverify_ok, X509_STORE_CTX *ctx)
} }
preverify_ok = true; preverify_ok = true;
} }
} } else {
else
{
fprintf(stderr, "Failing Normal Certificate!!!\n"); fprintf(stderr, "Failing Normal Certificate!!!\n");
preverify_ok = false; preverify_ok = false;
} }
if (preverify_ok) {
//add the cert to our collection if not already in it
bool found = false;
std::string certId;
{
RsStackMutex stack(sslMtx);
sslcert *cert = NULL;
getX509id(X509_STORE_CTX_get_current_cert(ctx), certId);
found = locked_FindCert(certId, &cert);
}
if (!found) {
std::cerr << "AuthSSL::VerifyX509Callback adding new SSL friend" << std::endl;
//first we want to ceate a new x509 because when SSL connection will be destroyed we will loose ref to the current x509
std::string copyCertstr;
BIO *bp = BIO_new(BIO_s_mem());
PEM_write_bio_X509(bp, X509_STORE_CTX_get_current_cert(ctx));
char *data;
int len = BIO_get_mem_data(bp, &data);
for(int i = 0; i < len; i++) {
copyCertstr += data[i];
}
BIO_free(bp);
//create a new x509 from the copyCertstr
char *certstr = strdup(copyCertstr.c_str());
BIO *bp2 = BIO_new_mem_buf(certstr, -1);
X509 *certCopy = PEM_read_bio_X509(bp2, NULL, NULL, NULL);
BIO_free(bp2);
free(certstr);
if (certCopy) {
AuthSSL::getAuthSSL()->ProcessX509(certCopy, certId);
mConnMgr->addFriend(certId);
}
}
//check that the peerid in the context is the same as the cert one
SSL *ssl = (SSL*) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
if (SSL_get_ex_data(ssl, AuthSSL::ex_data_ctx_index)) {
char *peer_id_in_context = (char*) SSL_get_ex_data(ssl, AuthSSL::ex_data_ctx_index);
if (std::string(certId.c_str()) != std::string(peer_id_in_context)) {
//the connection was asked for a given peer and get connected top another peer
fprintf(stderr, "AuthSSL::VerifyX509Callback peer id in context not the same as cert, aborting connection.");
preverify_ok = false;
//tranfer the ip address to the new peer
peerConnectState detail;
if (mConnMgr->getFriendNetStatus(peer_id_in_context, detail)) {
mConnMgr->setAddressList(certId, detail.getIpAddressList());
}
} else {
fprintf(stderr, "AuthSSL::VerifyX509Callback peer id in context is the same as cert, continung connection.");
}
}
}
if (preverify_ok) { if (preverify_ok) {
fprintf(stderr, "AuthSSL::VerifyX509Callback returned true.\n"); fprintf(stderr, "AuthSSL::VerifyX509Callback returned true.\n");
} else { } else {

View File

@ -57,6 +57,8 @@ typedef std::string SSL_id;
class AuthSSL; class AuthSSL;
class p3ConnectMgr;
class sslcert class sslcert
{ {
public: public:
@ -96,6 +98,7 @@ virtual int InitAuth(const char *srvr_cert, const char *priv_key,
const char *passwd); const char *passwd);
virtual bool CloseAuth(); virtual bool CloseAuth();
virtual int setConfigDirectories(std::string confFile, std::string neighDir); virtual int setConfigDirectories(std::string confFile, std::string neighDir);
SSL_CTX * getNewSslCtx();
/*********** Overloaded Functions from p3AuthMgr **********/ /*********** Overloaded Functions from p3AuthMgr **********/
@ -159,6 +162,7 @@ virtual bool ValidateCertificate(X509 *x509, std::string &peerId); /* validate
public: /* SSL specific functions used in pqissl/pqissllistener */ public: /* SSL specific functions used in pqissl/pqissllistener */
SSL_CTX *getCTX(); SSL_CTX *getCTX();
static int ex_data_ctx_index; //used to pass the peer id in the ssl context
bool FailedCertificate(X509 *x509, bool incoming); /* store for discovery */ bool FailedCertificate(X509 *x509, bool incoming); /* store for discovery */
@ -170,7 +174,9 @@ bool loadCertificates(bool &oldFormat, std::map<std::string, std::string> &key
static AuthSSL *getAuthSSL() throw() // pour obtenir l'instance static AuthSSL *getAuthSSL() throw() // pour obtenir l'instance
{ return instance_ssl; } { return instance_ssl; }
private: p3ConnectMgr *mConnMgr;
private:
// the single instance of this // the single instance of this
static AuthSSL *instance_ssl; static AuthSSL *instance_ssl;

View File

@ -945,7 +945,9 @@ int pqissl::Initiate_SSL_Connection()
// Perform SSL magic. // Perform SSL magic.
// library already inited by sslroot(). // library already inited by sslroot().
SSL *ssl = SSL_new(AuthSSL::getAuthSSL()->getCTX()); SSL_CTX *ssl_ctx = AuthSSL::getAuthSSL()->getCTX();
SSL *ssl = SSL_new(ssl_ctx);
if (ssl == NULL) if (ssl == NULL)
{ {
rslog(RSL_ALERT, pqisslzone, rslog(RSL_ALERT, pqisslzone,
@ -960,7 +962,11 @@ int pqissl::Initiate_SSL_Connection()
ssl_connection = ssl; ssl_connection = ssl;
net_internal_SSL_set_fd(ssl, sockfd); //store the peer id in the context for the callback check
AuthSSL::ex_data_ctx_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
SSL_set_ex_data(ssl, AuthSSL::ex_data_ctx_index, const_cast<char*> (PeerId().c_str()));
net_internal_SSL_set_fd(ssl, sockfd);
if (err < 1) if (err < 1)
{ {
std::ostringstream out; std::ostringstream out;
@ -1065,16 +1071,9 @@ int pqissl::Extract_Failed_SSL_Certificate()
"pqissl::Extract_Failed_SSL_Certificate()"); "pqissl::Extract_Failed_SSL_Certificate()");
// Get the Peer Certificate.... // Get the Peer Certificate....
/**************** PQI_USE_XPGP ******************/
#if defined(PQI_USE_XPGP)
XPGP *peercert = SSL_get_peer_pgp_certificate(ssl_connection);
#else /* X509 Certificates */
/**************** PQI_USE_XPGP ******************/
X509 *peercert = SSL_get_peer_certificate(ssl_connection); X509 *peercert = SSL_get_peer_certificate(ssl_connection);
#endif /* X509 Certificates */
/**************** PQI_USE_XPGP ******************/
if (peercert == NULL) if (peercert == NULL)
{ {
rslog(RSL_WARNING, pqisslzone, rslog(RSL_WARNING, pqisslzone,
"pqissl::Extract_Failed_SSL_Certificate() Peer Didnt Give Cert"); "pqissl::Extract_Failed_SSL_Certificate() Peer Didnt Give Cert");
@ -1158,7 +1157,7 @@ int pqissl::Authorise_SSL_Connection()
accept(ssl_connection, sockfd, remote_addr); accept(ssl_connection, sockfd, remote_addr);
return 1; return 1;
} }
{ {
std::ostringstream out; std::ostringstream out;

View File

@ -1886,6 +1886,7 @@ int RsServer::StartupRetroShare()
rsNotify = new p3Notify(); rsNotify = new p3Notify();
mConnMgr = new p3ConnectMgr(); mConnMgr = new p3ConnectMgr();
AuthSSL::getAuthSSL()->mConnMgr = mConnMgr;
//load all the SSL certs as friends //load all the SSL certs as friends
std::list<std::string> sslIds; std::list<std::string> sslIds;
AuthSSL::getAuthSSL()->getAuthenticatedList(sslIds); AuthSSL::getAuthSSL()->getAuthenticatedList(sslIds);