ssl.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           ssl.cpp  -  description
00003                              -------------------
00004     begin                : Thu Dec 9 2004
00005     copyright            : (C) 2004 by VooDooMan
00006     email                : vdmfun@hotmail.com
00007  ***************************************************************************/
00008 
00009 /* serv.cpp  -  Minimal ssleay server for Unix
00010    30.9.1996, Sampo Kellomaki <sampo@iki.fi> */
00011 
00012 
00013 /* mangled to work with SSLeay-0.9.0b and OpenSSL 0.9.2b
00014    Simplified to be even more minimal
00015    12/98 - 4/99 Wade Scholine <wades@mail.cybg.com> */
00016 
00017 #include <stdio.h>
00018 //#include <unistd.h>
00019 #include <stdlib.h>
00020 #include <memory.h>
00021 #include <errno.h>
00022 #include <sys/types.h>
00023 //#include <sys/socket.h>
00024 //#include <netinet/in.h>
00025 //#include <arpa/inet.h>
00026 //#include <netdb.h>
00027 
00028 #ifdef _WIN32
00029 #   include <winsock2.h>
00030 #else
00031 #    include <sys/time.h>
00032 #    include <sys/types.h>
00033 #    include <unistd.h>
00034 #endif
00035 
00036 #include <openssl/rsa.h>       /* SSLeay stuff */
00037 #include <openssl/crypto.h>
00038 #include <openssl/x509.h>
00039 #include <openssl/pem.h>
00040 #include <openssl/ssl.h>
00041 #include <openssl/err.h>
00042 
00043 #include <openssl/x509v3.h>
00044 
00045 #include <list>
00046 
00047 using namespace std;
00048 
00049 #include "ssl.h"
00050 #include "sock.h"
00051 #include "log.h"
00052 
00053 #include "params.h"
00054 
00055 /*!
00056     \file
00057     \brief Provides SSL socket communication
00058 */
00059 
00060 /*!
00061     \def verify_depth_
00062     \brief Depth of verifying chained certificates
00063 */
00064 #define verify_depth_    128
00065 
00066 s_ssl_conf ssl_conf;                                //!< Configuration of SSL
00067 
00068 /*!
00069     \brief Stores data for verification purposes
00070     \author VooDooMan
00071     \version 1
00072     \date 2004
00073 */
00074 typedef struct {
00075    int verbose_mode;                                //!< Verbose mode? (not using anymore)
00076    int verify_depth;                                //!< Verification depth
00077    int always_continue;                             //!< If set to true, it continues even if there's a verification error
00078    bool ok;                                         //!< If true, there's no verification error yet
00079    char err[1024];                                  //!< Verification error message
00080  } mydata_t;
00081 
00082 /*!
00083     \brief Stores extra data attached to SLL structure
00084     \author VooDooMan
00085     \version 1
00086     \date 2004
00087 */
00088 struct s_extra_data {
00089     SSL* ssl;                                       //!< SSL structure
00090     int index;                                      //!< Index of user data
00091 };
00092 
00093 vector<s_extra_data> extra_data;                    //!< Array of extra data attached to SSL structure
00094 
00095 /*!
00096     \brief Stores data to send/receive later
00097     \author VooDooMan
00098     \version 1
00099     \date 2004
00100 */
00101 struct s_ssl_data {
00102     int error;                          //!< Idicates that connection has error (if this is non-zero, data && len are undefined)
00103     size_t len;                         //!< Length of data
00104     char* data;                         //!< Data
00105 
00106     s_ssl_data()
00107     {
00108         error=0;
00109         len=0;
00110         data=NULL;
00111     }
00112 };
00113 
00114 /*!
00115     \brief Stores data to send later
00116     \author VooDooMan
00117     \version 1
00118     \date 2004
00119 */
00120 struct s_ssl_send_later {
00121     bool has_error;                     //!< Set to true, if we have data, but there's an error on the socket, or socket has been closed (by remote host)
00122     SSL* ssl;                           //!< SSL descriptor
00123     list<s_ssl_data> data;              //!< Array of data packets
00124 
00125     s_ssl_send_later()
00126     {
00127         has_error=false;
00128         ssl=NULL;
00129         data.clear();
00130     }
00131 };
00132 
00133 /*!
00134     \brief Stores data to receive later
00135     \author VooDooMan
00136     \version 1
00137     \date 2004
00138 */
00139 struct s_ssl_receive_later {
00140     bool has_error;                     //!< Set to true, if we have data, but there's an error on the socket, or socket has been closed (by remote host)
00141     SSL* ssl;                           //!< Socket handle
00142     list<s_ssl_data> data;              //!< Array of data packets
00143     s_socket s;                         //!< Socket descriptor of connection
00144     bool cert_verified;                 //!< Was certificate verified yet? true==YES, false==verification pending
00145     string expected_client_cert;        //!< Path to expected client's certificate
00146 
00147     s_ssl_receive_later()
00148     {
00149         has_error=false;
00150         ssl=NULL;
00151         data.clear();
00152         cert_verified=false;
00153         expected_client_cert="";
00154     }
00155 };
00156 
00157 vector<s_ssl_send_later> ssl_send_later;            //!< Packets to send later
00158 vector<s_ssl_receive_later> ssl_receive_later;      //!< Packets to receive later
00159 
00160 /*!
00161     \brief Generates error message
00162     \author VooDooMan
00163     \version 1
00164     \date 2004
00165     \param func Name of failed function
00166     \param err_str Original Error string, will be expanded
00167     \warning err_str must be at least 1024 bytes long!
00168 */
00169 void ssl_error(char* func, char* err_str)
00170 {
00171     char* tmp=new char[strlen(func)+strlen(err_str)+1024+1];
00172     strcpy(tmp,"while calling ");
00173     strcat(tmp,func);
00174     strcat(tmp,"() occured error ");
00175     strcat(tmp,err_str);
00176     if(strlen(tmp)>1023)
00177         tmp[1023]=0;
00178     strcpy(err_str,tmp);
00179     delete[] tmp;
00180 }
00181 
00182 /*!
00183     \brief Checks for success of certification verify
00184     \author VooDooMan
00185     \version 1
00186     \date 2004
00187     \param ssl SSL descriptor of connection
00188     \param err_str Returns error string if there was an error
00189     \warning err_str must be at least 1024 bytes long!
00190     \return true for error
00191 */
00192 bool ssl_verify_error(SSL* ssl, char* err_str)
00193 {
00194     mydata_t* mydata;
00195 
00196     int index=0;
00197     vector<s_extra_data>::iterator i1;
00198     for(i1=extra_data.begin(); i1!=extra_data.end(); i1++) {
00199         if((*i1).ssl==ssl) {
00200             index=(*i1).index;
00201             break;
00202         }
00203     }
00204     mydata = (mydata_t*) SSL_get_ex_data(ssl, index);
00205     if(mydata) {
00206         if(!mydata->ok && strlen(mydata->err))
00207             strcpy(err_str,mydata->err);
00208         if(!mydata->ok)
00209             return true;
00210     }
00211     return false;
00212 }
00213 
00214 /*!
00215     \brief Loads a certificate from file
00216     \author VooDooMan
00217     \version 1
00218     \date 2005
00219     \param filename Name of file
00220 */
00221 X509 *ssl_read_cert(char* filename)
00222 {
00223     X509* cert;
00224     BIO* s=BIO_new_file(filename,"r");
00225 
00226     if(!s)
00227         return NULL;
00228           
00229     BIO* f=BIO_new(BIO_f_base64());
00230     if(!f) {
00231         BIO_free(s);
00232         return NULL;
00233     }
00234     s=BIO_push(f,s);
00235     cert=d2i_X509_bio(s,NULL);
00236     BIO_free_all(s);
00237 
00238     return cert;
00239 }
00240 
00241 /*!
00242     \brief Logs a certificate verify error
00243     \author VooDooMan
00244     \version 1
00245     \date 2005
00246     \param ssl SSL descriptor of connection
00247     \retval true Returns true for error
00248     \return Returns true for error
00249 */
00250 bool ssl_process_error_on_verify(SSL* ssl)
00251 {
00252     int index=-1;
00253     vector<s_extra_data>::iterator i1;
00254     for(i1=extra_data.begin(); i1!=extra_data.end(); i1++) {
00255         if((*i1).ssl==ssl) {
00256             index=(*i1).index;
00257             break;
00258         }
00259     }
00260     if(index==-1)
00261         return false;
00262     mydata_t* mydata = (mydata_t*) SSL_get_ex_data(ssl, index);
00263     if(mydata) {
00264         if(!mydata->ok) {
00265             char err_str[1024];
00266             strncpy(err_str,mydata->err,sizeof(err_str));
00267             err_str[sizeof(err_str)-1]=0;
00268             ssl_error("(certificate verification callback)",err_str);
00269             log_ssl(err_str);
00270             return true;
00271         }
00272     }
00273     return false;
00274 }
00275 
00276 /*!
00277     \brief Performs cached reads and writes
00278     \author VooDooMan
00279     \version 1
00280     \date 2004
00281     \param ssl SSL descriptor of connection
00282 */
00283 void ssl_do_read_write(SSL* ssl)
00284 {
00285     char err_str[1024];
00286 
00287     vector<s_ssl_receive_later>::iterator i2;
00288     for(i2=ssl_receive_later.begin(); i2!=ssl_receive_later.end(); i2++) {
00289         if((*i2).ssl==ssl) {
00290             unsigned int max_size=1024*20;
00291             char* buf_=new char[max_size];
00292 
00293             timeval t;
00294             t.tv_sec=0;
00295             t.tv_usec=10;
00296 
00297             fd_set a;
00298             FD_ZERO(&a);
00299             FD_SET((*i2).s.handle,&a);
00300 
00301             int i=select((int)(*i2).s.handle+1,&a,NULL,NULL,&t);
00302             if(i==0) {
00303                 delete[] buf_;
00304                 break;
00305             }
00306 
00307             int err;
00308             try {
00309                 err=SSL_read (ssl, buf_, max_size);
00310             } catch(...) {
00311                 err=-1;
00312             }
00313             if(err==-1 && (ERR_get_error()==SSL_ERROR_WANT_READ || ERR_get_error()==SSL_ERROR_WANT_WRITE)) {
00314                 delete[] buf_;
00315                 break;
00316             }
00317             if(err==-1 && ERR_get_error()!=0) {
00318                 ERR_error_string(ERR_get_error(),err_str);
00319                 ssl_error("SSL_read",err_str);
00320                 log_ssl(err_str);
00321 
00322                 delete[] buf_;
00323                 if(!(*i2).has_error) {
00324                     s_ssl_data d;
00325                     d.error=ERR_get_error();
00326                     (*i2).data.push_back(d);
00327                     (*i2).has_error=true;
00328                     break;
00329                 }
00330             }
00331             if(!(*i2).has_error && ssl_process_error_on_verify(ssl)) {
00332                 s_ssl_data d;
00333                 d.data=NULL;
00334                 d.len=0;
00335                 d.error=-1;
00336                 (*i2).data.push_back(d);
00337                 (*i2).has_error=true;
00338             }
00339             size_t size_=((signed)err>0?err:0);
00340             if(size_==0) {
00341                 delete[] buf_;
00342                 break;
00343             }
00344             if(size_) {
00345                 s_ssl_data d;
00346                 d.error=0;
00347                 d.len=size_;
00348                 d.data=buf_;
00349                 (*i2).data.push_back(d);
00350 
00351                 if(!(*i2).cert_verified) {
00352                     X509* client_cert = SSL_get_peer_certificate (ssl);
00353                     if (client_cert != NULL) {
00354                         if (SSL_get_verify_result(ssl) == X509_V_OK) {
00355                             // The client sent a certificate which verified OK
00356                             bool ok=false;
00357                             if(!(*i2).expected_client_cert.empty()) {
00358                                 X509* ecc=ssl_read_cert((char*)(*i2).expected_client_cert.c_str());
00359                                 X509_check_purpose(ecc,-1,0); // compute SHA1 hash
00360                                 if(ecc==NULL) {
00361                                     ok=false;
00362                                 } else {
00363                                     char* hash1=(char*)&(ecc->sha1_hash);
00364                                     char* hash2=(char*)&(client_cert->sha1_hash);
00365                                     ok=true;
00366                                     for(int i1=0; i1<sizeof(client_cert->sha1_hash); i1++, hash1++, hash2++)
00367                                         if(*hash1!=*hash2) {
00368                                             ok=false;
00369                                             break;
00370                                         }
00371                                 }
00372                             } else
00373                                 ok=true;
00374                             if(ok) {
00375                                 (*i2).cert_verified=true;
00376                                 X509_free (client_cert);
00377                             } else {
00378                                 char err_str[1024];
00379                                 strcpy(err_str,"certificate verification failed");
00380                                 ssl_error("ssl_server_read",err_str);
00381                                 log_ssl(err_str);
00382                                 X509_free (client_cert);
00383                                 (*i2).has_error=true;
00384                                 s_ssl_data d;
00385                                 d.error=-1;
00386                                 d.len=0;
00387                                 d.data=NULL;
00388                                 (*i2).data.push_back(d);
00389                             }
00390                         } else {
00391                             char err_str[1024];
00392                             strcpy(err_str,"certificate verification failed");
00393                             ssl_error("ssl_server_read",err_str);
00394                             log_ssl(err_str);
00395                             X509_free (client_cert);
00396                             (*i2).has_error=true;
00397                             s_ssl_data d;
00398                             d.error=-1;
00399                             d.len=0;
00400                             d.data=NULL;
00401                             (*i2).data.push_back(d);
00402                         }
00403                     } else {
00404                         char err_str[1024];
00405                         strcpy(err_str,"certificate verification failed");
00406                         ssl_error("ssl_server_read",err_str);
00407                         log_ssl(err_str);
00408                         (*i2).has_error=true;
00409                         s_ssl_data d;
00410                         d.error=-1;
00411                         d.len=0;
00412                         d.data=NULL;
00413                         (*i2).data.push_back(d);
00414                     }
00415                 }
00416             }
00417         }
00418     }
00419 
00420     vector<s_ssl_send_later>::iterator i1;
00421     for(i1=ssl_send_later.begin(); i1!=ssl_send_later.end(); i1++) {
00422     again:
00423         list<s_ssl_data>::iterator i2;
00424         try {
00425             i2=(*i1).data.begin();
00426         } catch(...) {
00427             continue;
00428         }
00429         for(i2=(*i1).data.begin(); i2!=(*i1).data.end(); i2++) {
00430             size_t l=1024;
00431             if((*i2).len<l)
00432                 l=(*i2).len;
00433 
00434             size_t Sent;
00435             //int err;
00436             try {
00437                 Sent=SSL_write (ssl, (*i2).data, (int)(*i2).len);
00438             } catch(...) {
00439                 Sent=(size_t)-1;
00440             }
00441             if(Sent==(size_t)-1 && ERR_get_error()!=SSL_ERROR_WANT_READ && ERR_get_error()!=SSL_ERROR_WANT_WRITE) {
00442                 if(!(*i1).has_error && ERR_get_error()!=0) {
00443                     ERR_error_string(ERR_get_error(),err_str);
00444                     ssl_error("SSL_write",err_str);
00445                     log_ssl(err_str);
00446                     s_ssl_data d;
00447                     d.data=NULL;
00448                     d.len=0;
00449                     d.error=ERR_get_error();
00450                     (*i1).data.push_back(d);
00451                     (*i1).has_error=true;
00452                 }
00453                 if(!(*i1).has_error && ssl_process_error_on_verify(ssl)) {
00454                     s_ssl_data d;
00455                     d.data=NULL;
00456                     d.len=0;
00457                     d.error=-1;
00458                     (*i1).data.push_back(d);
00459                     (*i1).has_error=true;
00460                 }
00461                 break;
00462             }
00463             if((signed)Sent<0)
00464                 Sent=0;
00465 
00466             if(Sent<(*i2).len) {
00467                 char* buf_=new char[(*i2).len-Sent];
00468                 memcpy(buf_,&(*i2).data[Sent],(*i2).len-Sent);
00469                 delete[] (*i2).data;
00470                 (*i2).len-=Sent;
00471                 (*i2).data=buf_;
00472             } else {
00473                 delete[] (*i2).data;
00474                 (*i1).data.pop_front();
00475             }
00476             goto again;
00477         }
00478     }
00479 }
00480 
00481 /*!
00482     \brief Performs read from read cache
00483     \author VooDooMan
00484     \version 1
00485     \date 2004
00486     \param ssl SSL descriptor of connection
00487     \param data Buffer to receive data
00488     \param size Size of that buffer
00489     \param read Returns number of bytes actually read
00490     \return Returns error from ERR_get_error() from OpenSSL
00491 */
00492 int SSL_read_(SSL* ssl, char* data, size_t size, size_t &read)
00493 {
00494     read=0;
00495     {
00496         vector<s_ssl_receive_later>::iterator i1;
00497         for(i1=ssl_receive_later.begin(); i1!=ssl_receive_later.end(); i1++) {
00498             if((*i1).ssl==ssl) {
00499                 list<s_ssl_data>::iterator i2;
00500                 for(i2=(*i1).data.begin(); i2!=(*i1).data.end(); i2++) {
00501                     int error_code=(*i2).error;
00502                     if(error_code)
00503                         return error_code;
00504 
00505                     size_t l=size;
00506                     if((*i2).len<=l) {
00507                         l=(*i2).len;
00508                         if((*i2).len)
00509                             memcpy(data,(*i2).data,l);
00510                         delete[] (*i2).data;
00511                         (*i1).data.pop_front();
00512                         read=l;
00513                         return 0;
00514                     }
00515                     if((*i2).len>l) {
00516                         memcpy(data,(*i2).data,l);
00517                         char* buf=new char[(*i2).len-l];
00518                         memcpy(buf,&((*i2).data[l]),(*i2).len-l);
00519                         delete[] (*i2).data;
00520                         (*i2).len-=l;
00521                         (*i2).data=buf;
00522                         error_code=0;
00523                         read=l;
00524                         return 0;
00525                     }
00526                 }
00527                 return 0;
00528             }
00529         }
00530     }
00531     return 0;
00532 }
00533 
00534 /*!
00535     \brief Performs write to the write cache
00536     \author VooDooMan
00537     \version 1
00538     \date 2004
00539     \param ssl SSL descriptor of connection
00540     \param data Buffer to send data
00541     \param size Size of that buffer
00542     \return Always returns value of size parameter
00543 */
00544 size_t SSL_write_(SSL* ssl, char* data, size_t size)
00545 {
00546     {
00547         {
00548 
00549             {
00550             again:
00551                 bool got=false;
00552                 vector<s_ssl_send_later>::iterator i1;
00553                 for(i1=ssl_send_later.begin(); i1!=ssl_send_later.end(); i1++) {
00554                     if((*i1).ssl==ssl) {
00555                         got=true;
00556                         break;
00557                     }
00558                 }
00559                 if(!got) {
00560                     s_ssl_send_later s;
00561                     s.ssl=ssl;
00562                     s.data.clear();
00563                     s.has_error=false;
00564                     ssl_send_later.push_back(s);
00565                     goto again;
00566                 }
00567                 s_ssl_data d;
00568                 d.error=0;
00569                 d.len=size;
00570                 d.data=new char[size];
00571                 memcpy(d.data,data,size);
00572                 (*i1).data.push_back(d);
00573 
00574                 return size;
00575             }
00576         }
00577     }
00578 }
00579 
00580 /*!
00581     \brief SSL verification callback
00582     \author Sampo Kellomaki <sampo@iki.fi>; Wade Scholine <wades@mail.cybg.com>; VooDooMan
00583     \version 1
00584     \date 1996-1998, 2004
00585     \param preverify_ok I don't actually know what the OpenSSL wants to say by this parameter ;-)
00586     \param ctx Context of stored certificates
00587     \return Returns 1 (one) to continue the verification process, 0 (zero) to terminate
00588 */
00589 static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
00590 {
00591     char    buf__[256];
00592     X509   *err_cert;
00593     int     err, depth;
00594     SSL    *ssl;
00595     mydata_t *mydata;
00596 
00597     err_cert = X509_STORE_CTX_get_current_cert(ctx);
00598     err = X509_STORE_CTX_get_error(ctx);
00599     depth = X509_STORE_CTX_get_error_depth(ctx);
00600 
00601     /*
00602      * Retrieve the pointer to the SSL of the connection currently treated
00603      * and the application specific data stored into the SSL object.
00604      */
00605     ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
00606 
00607     int index=0;
00608     vector<s_extra_data>::iterator i1;
00609     for(i1=extra_data.begin(); i1!=extra_data.end(); i1++) {
00610         if((*i1).ssl==ssl) {
00611             index=(*i1).index;
00612             break;
00613         }
00614     }
00615     mydata = (mydata_t*) SSL_get_ex_data(ssl, index);
00616 
00617     X509_NAME_oneline(X509_get_subject_name(err_cert), buf__, 256);
00618 
00619     /*
00620      * Catch a too long certificate chain. The depth limit set using
00621      * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
00622      * that whenever the "depth>verify_depth" condition is met, we
00623      * have violated the limit and want to log this error condition.
00624      * We must do it here, because the CHAIN_TOO_LONG error would not
00625      * be found explicitly; only errors introduced by cutting off the
00626      * additional certificates would be logged.
00627      */
00628     if (depth > mydata->verify_depth) {
00629         preverify_ok = 0;
00630         err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
00631         X509_STORE_CTX_set_error(ctx, err);
00632     }
00633     if (!preverify_ok) {
00634         mydata->ok=false;
00635         sprintf(mydata->err,"verify error:num=%d:%s:depth=%d:%s\n", err,
00636                  X509_verify_cert_error_string(err), depth, buf__);
00637     }
00638     else if (mydata->verbose_mode)
00639     {
00640         //printf("depth=%d:%s\n", depth, buf__);
00641     }
00642 
00643     /*
00644      * At this point, err contains the last verification error. We can use
00645      * it for something special
00646      */
00647     if (!preverify_ok && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
00648     {
00649         X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf__, 256);
00650         //printf("issuer= %s\n", buf__);
00651     }
00652 
00653     if (mydata->always_continue)
00654         return 1;
00655     else
00656         return preverify_ok;
00657 }
00658 
00659 SSL_CTX* ctx;                               //!< SSL context, unique for program's lifetime
00660 SSL_METHOD *meth;                           //!< SSL method for context
00661 
00662 /*!
00663     \brief Initializes OpenSSL
00664     \author VooDooMan
00665     \version 1
00666     \date 2004
00667     \param err_str If return value is true, there's error string
00668     \param trustedCAs Path to file containing certificates of CA's tu trust
00669     \return true for error
00670 */
00671 bool ssl_init(char* err_str, char* trustedCAs)
00672 {
00673     /* SSL preliminaries. We keep the certificate and key with the context. */
00674 
00675     SSL_load_error_strings();
00676 
00677     SSL_library_init();                      /* initialize library */
00678     //actions_to_seed_PRNG();
00679 
00680     SSLeay_add_ssl_algorithms();
00681     meth = SSLv3_method();
00682     ctx = SSL_CTX_new (meth);
00683 
00684     if (!ctx) {
00685         //ERR_print_errors_fp(stderr);
00686         ERR_error_string(ERR_get_error(),err_str);
00687         ssl_error("SSL_CTX_new",err_str);
00688         log_ssl(err_str);
00689         return true;
00690     }
00691 
00692     STACK_OF(X509_NAME) *cert_names=SSL_load_client_CA_file(trustedCAs);
00693     if(!cert_names) {
00694         ERR_error_string(ERR_get_error(),err_str);
00695         ssl_error("SSL_load_client_CA_file",err_str);
00696         if(strlen(err_str)+strlen(trustedCAs)+64<1024) {
00697             strcat(err_str,"(using file \"");
00698             strcat(err_str,trustedCAs);
00699             strcat(err_str,"\")");
00700         }
00701         log_ssl(err_str);
00702         return true;
00703     }
00704     SSL_CTX_set_client_CA_list(ctx,cert_names);
00705 
00706     if(!SSL_CTX_load_verify_locations(ctx,trustedCAs,NULL)) {
00707         ERR_error_string(ERR_get_error(),err_str);
00708         ssl_error("SSL_CTX_load_verify_locations",err_str);
00709         log_ssl(err_str);
00710         return true;
00711     }
00712 
00713     SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,verify_callback);
00714     SSL_CTX_set_verify_depth(ctx,verify_depth_ + 1);
00715 
00716     return false;
00717 }
00718 
00719 /*!
00720     \brief Attaches socket connection to OpenSSL
00721     \author VooDooMan
00722     \version 1
00723     \date 2004
00724     \param ssl Returns SSL descriptor, if succeeded
00725     \param client Socket descriptor to attach
00726     \param err_str If return value is true, there's error string
00727     \param server_cert Path to file containing server's certificate chain to use for connection
00728     \param server_key Private key for server's certificate
00729     \param expected_client_cert Path to file containing expected client's certificate
00730     \return true for error
00731 */
00732 bool ssl_server_connection(SSL* &ssl, s_socket* client, char* err_str, char* server_cert, char* server_key, char* expected_client_cert)
00733 {
00734     ssl = SSL_new (ctx);
00735     if(!ssl) {
00736         strcpy(err_str,"attempt to use NULL SSL handle");
00737         ssl_error("SSL_new",err_str);
00738         log_ssl(err_str);
00739         return true;
00740     }
00741 
00742     /*SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,verify_callback);
00743     SSL_set_verify_depth(ssl,verify_depth_ + 1);*/
00744   
00745     /*
00746      * Set up the SSL specific data into "mydata" and store it into th SSL
00747      * structure.
00748      */
00749 
00750     if (SSL_use_certificate_file(ssl, server_cert, SSL_FILETYPE_PEM) <= 0) {
00751         ERR_error_string(ERR_get_error(),err_str);
00752         ssl_error("SSL_use_certificate_file",err_str);
00753         log_ssl(err_str);
00754         return true;
00755     }
00756     if (SSL_use_RSAPrivateKey_file(ssl, server_key, SSL_FILETYPE_PEM) <= 0) {
00757         ERR_error_string(ERR_get_error(),err_str);
00758         ssl_error("SSL_use_RSAPrivateKey_file",err_str);
00759         log_ssl(err_str);
00760         return true;
00761     }
00762 
00763     if (!SSL_check_private_key(ssl)) {
00764         sprintf(err_str,"Private key does not match the certificate public key\n");
00765         ssl_error("SSL_check_private_key",err_str);
00766         log_ssl(err_str);
00767         return true;
00768     }
00769 
00770     int mydata_index = SSL_get_ex_new_index(0,NULL , NULL, NULL, NULL);
00771     client->ssl_data_index=mydata_index;
00772     s_extra_data e;
00773     e.ssl=ssl;
00774     e.index=mydata_index;
00775     extra_data.push_back(e);
00776 
00777     mydata_t* mydata=new mydata_t;
00778     mydata->verify_depth = verify_depth_;
00779     mydata->always_continue=false;
00780     mydata->verbose_mode=false;
00781     mydata->ok=true;
00782     mydata->err[0]=0;
00783     SSL_set_ex_data(ssl, mydata_index, mydata);
00784 
00785     SSL_set_fd (ssl, (int)client->handle);
00786 
00787     {
00788         s_ssl_receive_later r;
00789         r.data.clear();
00790         r.has_error=false;
00791         r.ssl=ssl;
00792         r.s=*client;
00793         r.cert_verified=false;
00794         r.expected_client_cert=expected_client_cert;
00795         ssl_receive_later.push_back(r);
00796     }
00797 
00798     return false;
00799 }
00800 
00801 /*!
00802     \brief Reads from cache
00803     \author VooDooMan
00804     \version 1
00805     \date 2004
00806     \param ssl SSL descriptor of connection
00807     \param client Socket descriptor of connection
00808     \param err_str If return value is true, there's error string
00809     \param buf Buffer for read
00810     \param buf_len Length of that buffer
00811     \param buf_got Returns number of bytes actually read
00812     \return true for error
00813 */
00814 bool ssl_server_read(SSL* ssl, s_socket* client, char* err_str, char* buf, size_t buf_len, size_t &buf_got)
00815 {
00816     buf_got=0;
00817 
00818     if(!ssl) {
00819         strcpy(err_str,"attempt to use NULL SSL handle");
00820         ssl_error("ssl_server_read",err_str);
00821         log_ssl(err_str);
00822         return true;
00823     }
00824 
00825     int err;
00826 
00827     if(!client->ssl_accepted) {
00828         timeval t;
00829         t.tv_sec=0;
00830         t.tv_usec=10;
00831         fd_set a;
00832         FD_ZERO(&a);
00833         FD_SET(client->handle,&a);
00834         int ii=select((int)client->handle+1,&a,NULL,NULL,&t);
00835         if(ii==0)
00836             return false;
00837         err = SSL_accept (ssl);
00838         /*if(err==-1) {
00839             return false;
00840         }*/
00841         client->ssl_accepted=true;
00842     }
00843 
00844     /* Get the cipher - opt */
00845 
00846     //printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
00847   
00848     /* Get client's certificate (note: beware of dynamic allocation) - opt */
00849 
00850     /*if (client_cert != NULL) {
00851         //printf ("Client certificate:\n");
00852     
00853         str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
00854         if(!str)
00855             return true;
00856         //printf ("\t subject: %s\n", str);
00857         OPENSSL_free (str);
00858     
00859         str = X509_NAME_oneline (X509_get_issuer_name  (client_cert), 0, 0);
00860         if(!str)
00861             return true;
00862         //printf ("\t issuer: %s\n", str);
00863         OPENSSL_free (str);
00864     
00865         /* We could do all sorts of certificate verification stuff here before
00866            deallocating the certificate. *
00867 
00868         X509_free (client_cert);
00869     } else
00870         //printf ("Client does not have certificate.\n");
00871         ;*/
00872 
00873     /* DATA EXCHANGE - Receive message and send reply. */
00874 
00875     mydata_t* mydata = (mydata_t*) SSL_get_ex_data(ssl, client->ssl_data_index);
00876 
00877     if(!mydata->ok) {
00878         strcpy(err_str,"certificate verification failed");
00879         ssl_error("ssl_server_read",err_str);
00880         log_ssl(err_str);
00881         return true;
00882     }
00883 
00884     ssl_do_read_write(ssl);
00885 
00886     size_t read;
00887     err = SSL_read_ (ssl, buf, buf_len,read);
00888 
00889     if(err!=0) {
00890         ERR_error_string(err,err_str);
00891         ssl_error("SSL_read",err_str);
00892         log_ssl(err_str);
00893         if(ssl_verify_error(ssl,err_str))
00894             log_ssl(err_str);
00895         return true;
00896     }
00897     buf_got=read;
00898     return false;
00899 }
00900 
00901 /*!
00902     \brief Closes the SSL connection in OpenSSL (not socket)
00903     \author VooDooMan
00904     \version 1
00905     \date 2004
00906     \param ssl SSL descriptor of connection
00907     \param peer Socket descriptor of connection
00908 */
00909 void ssl_close(SSL* ssl, s_socket* peer)
00910 {
00911     if(!ssl)
00912         return;
00913 
00914     {
00915         vector<s_ssl_send_later>::iterator i1;
00916         for(i1=ssl_send_later.begin(); i1!=ssl_send_later.end(); i1++) {
00917             if((*i1).ssl==ssl) {
00918                 list<s_ssl_data>::iterator i;
00919                 for(i=(*i1).data.begin(); i!=(*i1).data.end(); i++)
00920                     delete[] (*i).data;
00921                 (*i1).data.clear();
00922                 ssl_send_later.erase(i1);
00923                 break;
00924             }
00925         }
00926 
00927         vector<s_ssl_receive_later>::iterator i2;
00928         for(i2=ssl_receive_later.begin(); i2!=ssl_receive_later.end(); i2++) {
00929             if((*i2).ssl==ssl) {
00930                 list<s_ssl_data>::iterator i;
00931                 for(i=(*i2).data.begin(); i!=(*i2).data.end(); i++)
00932                     delete[] (*i).data;
00933                 (*i2).data.clear();
00934                 ssl_receive_later.erase(i2);
00935                 break;
00936             }
00937         }
00938     }
00939 
00940     mydata_t* mydata = (mydata_t*) SSL_get_ex_data(ssl, peer->ssl_data_index);
00941     if(mydata)
00942         delete mydata;
00943     vector<s_extra_data>::iterator i1;
00944     for(i1=extra_data.begin(); i1!=extra_data.end(); i1++) {
00945         if((*i1).ssl==ssl) {
00946             extra_data.erase(i1);
00947             break;
00948         }
00949     }
00950     SSL_free (ssl);
00951 }
00952 
00953 /*!
00954     \brief Attaches socket of client connected to server to OpenSSL
00955     \author VooDooMan
00956     \version 1
00957     \date 2004
00958     \param ssl Receives SSL descriptor of connection
00959     \param server Socket descriptor of connection
00960     \param err_str If return value is true, there's error string
00961     \param client_cert Path to file containing client's certificate chain to use for connection
00962     \param client_key Private key for clients's certificate
00963     \return true for error
00964 */
00965 bool ssl_client_connection(SSL* &ssl, s_socket* server, char* err_str, char* client_cert, char* client_key)
00966 {
00967     server->ssl_accepted=true;
00968 
00969     int err;
00970 
00971     //X509*    server_cert;
00972 
00973     ssl = SSL_new (ctx);
00974     if(!ssl) {
00975         strcpy(err_str,"attempt to use NULL SSL handle");
00976         ssl_error("ssl_client_connection",err_str);
00977         log_ssl(err_str);
00978         return true;
00979     }
00980 
00981     SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,verify_callback);
00982     SSL_set_verify_depth(ssl,verify_depth_ + 1);
00983 
00984     if (SSL_use_certificate_file(ssl, client_cert, SSL_FILETYPE_PEM) <= 0) {
00985         ERR_error_string(ERR_get_error(),err_str);
00986         ssl_error("SSL_use_certificate_file",err_str);
00987         log_ssl(err_str);
00988         return true;
00989     }
00990     if (SSL_use_RSAPrivateKey_file(ssl, client_key, SSL_FILETYPE_PEM) <= 0) {
00991         ERR_error_string(ERR_get_error(),err_str);
00992         ssl_error("SSL_use_RSAPrivateKey_file",err_str);
00993         log_ssl(err_str);
00994         return true;
00995     }
00996 
00997     if (!SSL_check_private_key(ssl)) {
00998         sprintf(err_str,"Private key does not match the certificate public key\n");
00999         ssl_error("SSL_check_private_key",err_str);
01000         log_ssl(err_str);
01001         return true;
01002     }
01003 
01004     int mydata_index = SSL_get_ex_new_index(0,NULL , NULL, NULL, NULL);
01005     server->ssl_data_index=mydata_index;
01006     s_extra_data e;
01007     e.ssl=ssl;
01008     e.index=mydata_index;
01009     extra_data.push_back(e);
01010 
01011     mydata_t* mydata=new mydata_t;
01012     mydata->verify_depth = verify_depth_;
01013     mydata->always_continue=false;
01014     mydata->verbose_mode=false;
01015     mydata->ok=true;
01016     SSL_set_ex_data(ssl, mydata_index, mydata);
01017 
01018     SSL_set_fd (ssl, (int)server->handle);
01019     err = SSL_connect (ssl);
01020     if(err==-1 && ERR_get_error()!=0) {
01021         ERR_error_string(ERR_get_error(),err_str);
01022         ssl_error("SSL_connect",err_str);
01023         log_ssl(err_str);
01024         if(ssl_verify_error(ssl,err_str))
01025             log_ssl(err_str);
01026         return true;
01027     }
01028 
01029     /* Following two steps are optional and not required for
01030        data exchange to be successful. */
01031   
01032     /* Get the cipher - opt */
01033 
01034     //printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
01035   
01036     /* Get server's certificate (note: beware of dynamic allocation) - opt */
01037 
01038     /*server_cert = SSL_get_peer_certificate (ssl);
01039     if(!server_cert)
01040         return true;
01041   
01042     str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
01043     if(!str)
01044         return true;
01045     OPENSSL_free (str);
01046 
01047     str = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);
01048     if(!str)
01049         return true;
01050     OPENSSL_free (str);
01051 
01052     /* We could do all sorts of certificate verification stuff here before
01053        deallocating the certificate. *
01054 
01055     X509_free (server_cert);*/
01056 
01057     /* --------------------------------------------------- */
01058     /* DATA EXCHANGE - Send a message and receive a reply. */
01059 
01060     {
01061         s_ssl_receive_later r;
01062         r.data.clear();
01063         r.has_error=false;
01064         r.ssl=ssl;
01065         r.s=*server;
01066         r.cert_verified=false;
01067         r.expected_client_cert="";
01068         ssl_receive_later.push_back(r);
01069     }
01070 
01071     return false;
01072 }
01073 
01074 /*!
01075     \brief Reads from cache
01076     \author VooDooMan
01077     \version 1
01078     \date 2004
01079     \param ssl SSL descriptor of connection
01080     \param client Socket descriptor of connection
01081     \param err_str If return value is true, there's error string
01082     \param buf Buffer for read
01083     \param buf_len Length of that buffer
01084     \param buf_got Returns number of bytes actually read
01085     \return true for error
01086 */
01087 bool ssl_client_read(SSL* ssl, s_socket* client, char* err_str, char* buf, size_t buf_len, size_t &buf_got)
01088 {
01089     return ssl_server_read(ssl,client,err_str,buf,buf_len,buf_got);
01090 }
01091 
01092 /*!
01093     \brief Writes to send cache
01094     \author VooDooMan
01095     \version 1
01096     \date 2004
01097     \param ssl SSL descriptor of connection
01098     \param peer Socket descriptor of connection
01099     \param err_str If return value is true, there's error string
01100     \param buf Buffer for read
01101     \param buf_len Length of that buffer
01102     \return true for error
01103 */
01104 bool ssl_write(SSL* ssl, s_socket* peer, char* err_str, char* buf, size_t buf_len)
01105 {
01106     if(!ssl) {
01107         strcpy(err_str,"attempt to use NULL SSL handle");
01108         ssl_error("ssl_write",err_str);
01109         log_ssl(err_str);
01110         return true;
01111     }
01112 
01113     mydata_t* mydata = (mydata_t*) SSL_get_ex_data(ssl, peer->ssl_data_index);
01114 
01115     if(!mydata->ok) {
01116         strcpy(err_str,"certificate verification failed");
01117         ssl_error("ssl_write",err_str);
01118         log_ssl(err_str);
01119         return true;
01120     }
01121 
01122     ssl_do_read_write(ssl);
01123 
01124     /*size_t err = */SSL_write_ (ssl, buf, buf_len);
01125     if(ssl_verify_error(ssl,err_str)) {
01126         log_ssl(err_str);
01127         return true;
01128     }
01129     /*if(err==-1 && ERR_get_error()!=SSL_ERROR_WANT_READ && ERR_get_error()!=SSL_ERROR_WANT_WRITE) {
01130         ERR_error_string(ERR_get_error(),err_str);
01131         log_ssl(err_str);
01132         return true;
01133     }*/
01134     return false;
01135 }
01136 
01137 /*!
01138     \brief Accepts incomming client connection in OpenSSL
01139     \author VooDooMan
01140     \version 1
01141     \date 2004
01142     \param ssl SSL descriptor of connection
01143     \param client Socket descriptor of connection
01144     \return true if connection has been accepted, otherwise false
01145 */
01146 bool ssl_server_accept(SSL* ssl, s_socket* client)
01147 {
01148     if(!ssl)
01149         return false;
01150 
01151     int err;
01152 
01153     if(!client->ssl_accepted) {
01154         timeval t;
01155         t.tv_sec=0;
01156         t.tv_usec=10;
01157         fd_set a;
01158         FD_ZERO(&a);
01159         FD_SET(client->handle,&a);
01160         int ii=select((int)client->handle+1,&a,NULL,NULL,&t);
01161         if(ii==0)
01162             return false;
01163         err = SSL_accept (ssl);
01164         /*if(err==-1) {
01165             char err_str[1024];
01166             ERR_error_string(ERR_get_error(),err_str);
01167             //log_ssl(err_str);
01168             return false;
01169         }*/
01170         return client->ssl_accepted=true;
01171     }
01172     return true;
01173 }
01174 

Generated on Sun Jul 10 03:23:03 2005 for VooDoo cIRCle by doxygen 1.4.3

Hosted by SourceForge.net Logo