From 485f27dc11ea7820ae9abefde4f871910020bece Mon Sep 17 00:00:00 2001 From: joss17 Date: Wed, 13 Jan 2010 21:16:56 +0000 Subject: [PATCH] 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 --- libretroshare/src/pqi/authssl.cc | 127 +++++++++++++++++++++++++-- libretroshare/src/pqi/authssl.h | 8 +- libretroshare/src/pqi/pqissl.cc | 21 +++-- libretroshare/src/rsserver/rsinit.cc | 1 + 4 files changed, 139 insertions(+), 18 deletions(-) diff --git a/libretroshare/src/pqi/authssl.cc b/libretroshare/src/pqi/authssl.cc index d068808de..14ac5d859 100644 --- a/libretroshare/src/pqi/authssl.cc +++ b/libretroshare/src/pqi/authssl.cc @@ -33,6 +33,7 @@ #include "pqinetwork.h" #include "authgpg.h" +#include "pqi/p3connmgr.h" /******************** notify of new Cert **************************/ #include "pqinotify.h" @@ -52,6 +53,10 @@ // initialisation du pointeur de singleton à zéro 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) { certificate = x509; @@ -587,6 +592,36 @@ SSL_CTX *AuthSSL::getCTX() 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) { #ifdef AUTHSSL_DEBUG @@ -1880,13 +1915,37 @@ X509 *AuthSSL::SignX509Req(X509_REQ *req, long days) bool AuthSSL::AuthX509(X509 *x509) { + fprintf(stderr, "AuthSSL::AuthX509() called\n"); + RsStackMutex stack(sslMtx); /******* LOCKED ******/ /* extract CN for peer Id */ - X509_NAME *issuer = X509_get_issuer_name(x509); - std::string id = ""; + std::string issuer = getX509CNString(x509->cert_info->issuer); + //check that the issuer is in the accepted GPG key list. + std::list acceptedIds; + AuthGPG::getAuthGPG()->getPGPAcceptedList(acceptedIds); + bool isAccepted = false; + for(std::list::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::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) ***/ 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; } - } - else - { + } else { fprintf(stderr, "Failing Normal Certificate!!!\n"); 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) { fprintf(stderr, "AuthSSL::VerifyX509Callback returned true.\n"); } else { diff --git a/libretroshare/src/pqi/authssl.h b/libretroshare/src/pqi/authssl.h index 8a286db44..6d903adea 100644 --- a/libretroshare/src/pqi/authssl.h +++ b/libretroshare/src/pqi/authssl.h @@ -57,6 +57,8 @@ typedef std::string SSL_id; class AuthSSL; +class p3ConnectMgr; + class sslcert { public: @@ -96,6 +98,7 @@ virtual int InitAuth(const char *srvr_cert, const char *priv_key, const char *passwd); virtual bool CloseAuth(); virtual int setConfigDirectories(std::string confFile, std::string neighDir); +SSL_CTX * getNewSslCtx(); /*********** 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 */ 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 */ @@ -170,7 +174,9 @@ bool loadCertificates(bool &oldFormat, std::map &key static AuthSSL *getAuthSSL() throw() // pour obtenir l'instance { return instance_ssl; } - private: + p3ConnectMgr *mConnMgr; + + private: // the single instance of this static AuthSSL *instance_ssl; diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index fbfbe7f3e..020e8977d 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -945,7 +945,9 @@ int pqissl::Initiate_SSL_Connection() // Perform SSL magic. // 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) { rslog(RSL_ALERT, pqisslzone, @@ -960,7 +962,11 @@ int pqissl::Initiate_SSL_Connection() 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 (PeerId().c_str())); + + net_internal_SSL_set_fd(ssl, sockfd); if (err < 1) { std::ostringstream out; @@ -1065,16 +1071,9 @@ int pqissl::Extract_Failed_SSL_Certificate() "pqissl::Extract_Failed_SSL_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); -#endif /* X509 Certificates */ -/**************** PQI_USE_XPGP ******************/ - if (peercert == NULL) + if (peercert == NULL) { rslog(RSL_WARNING, pqisslzone, "pqissl::Extract_Failed_SSL_Certificate() Peer Didnt Give Cert"); @@ -1158,7 +1157,7 @@ int pqissl::Authorise_SSL_Connection() accept(ssl_connection, sockfd, remote_addr); return 1; - } + } { std::ostringstream out; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index c8c837b75..41abc5fa7 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1886,6 +1886,7 @@ int RsServer::StartupRetroShare() rsNotify = new p3Notify(); mConnMgr = new p3ConnectMgr(); + AuthSSL::getAuthSSL()->mConnMgr = mConnMgr; //load all the SSL certs as friends std::list sslIds; AuthSSL::getAuthSSL()->getAuthenticatedList(sslIds);