"Fossies" - the Fresh Open Source Software Archive

Member "tlswrap-1.04/tls.c" (25 Nov 2006, 14513 Bytes) of package /linux/privat/old/tlswrap-1.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tls.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 2002-2006 Tomas Svensson <ts@codepix.com>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
   17  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   18  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
   19  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <stdio.h>
   29 #include <stdlib.h>
   30 #include <string.h>
   31 #include <sys/types.h>
   32 #ifdef WIN32
   33 #include <Winsock2.h>
   34 #define snprintf _snprintf
   35 #define strcasecmp _stricmp
   36 #else
   37 #include <unistd.h>
   38 #include <syslog.h>
   39 #include <arpa/ftp.h>
   40 #include <sys/time.h>
   41 #include <netinet/in.h>
   42 #include <pwd.h>
   43 #endif
   44 #include <ctype.h>
   45 #include <openssl/ssl.h>
   46 #include <openssl/rand.h>
   47 #include <openssl/err.h>
   48 #include <openssl/x509v3.h>
   49 #include <fcntl.h>
   50 
   51 #include "tlswrap.h"
   52 #include "tls.h"
   53 #include "misc.h"
   54 
   55 extern int debug;
   56 /* extern int sec_mode; 
   57 
   58 int global_user_cert;
   59 X509_STORE *ca_store; */
   60 
   61 void tls_init(char *egd_sock) {
   62 
   63     if (!SSL_library_init())
   64         sys_err("OpenSSL initialization failed");
   65 
   66     SSL_load_error_strings(); /* load readable error messages */
   67 /*
   68     if (!(tls_ctx = SSL_CTX_new(SSLv23_method()))) {
   69         printf("SSL_CTX_new() %s\r\n",(char *)ERR_error_string(ERR_get_error(), NULL));
   70         exit(1);
   71     }*/
   72     if (debug)
   73         printf("egd_sock is %s\n", egd_sock);
   74 #ifdef HAVE_RAND_STATUS
   75     if (RAND_status() != 1) {
   76         if ( RAND_egd(egd_sock) == -1 ) {
   77             fprintf(stderr, "egd_sock is %s\n", egd_sock);
   78             sys_err("RAND_egd failed\n");
   79         }
   80         if (RAND_status() != 1)
   81             sys_err("ssl_init: System without /dev/urandom, PRNG seeding must be done manually.\r\n");
   82     }
   83 #endif
   84     /*
   85     SSL_CTX_set_options(tls_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
   86     SSL_CTX_set_default_verify_paths(tls_ctx);
   87     */
   88 //  global_user_cert = 0;
   89 
   90     /*
   91     if (sec_mode > 0) {
   92         if (SSL_CTX_use_certificate_chain_file(tls_ctx, "usercert.pem") == 1) {
   93             if (SSL_CTX_use_PrivateKey_file(tls_ctx, "usercert.pem", SSL_FILETYPE_PEM) != 1)
   94                 sys_err("Unable to load private key from file.");
   95             else
   96                 global_user_cert = 1;
   97             if (debug)
   98                 printf("Global user certificate chain loaded.\n");
   99         } else {
  100             if (debug)
  101                 printf("No global user certificate loaded.\n");
  102     }
  103     */
  104   
  105     /*
  106     if (cafile[0] != '\0') { // CA verifications. 
  107         if (SSL_CTX_load_verify_locations(tls_ctx, cafile, NULL) != 1)
  108             sys_err("could not load certificates from CA file.");
  109         else if (debug)
  110             printf("Loaded CA file.\n");
  111         ca_store = SSL_CTX_get_cert_store(tls_ctx);
  112     } else
  113         ca_store = NULL;
  114 
  115     SSL_CTX_set_cert_store(tls_ctx, NULL);
  116     SSL_CTX_free(tls_ctx);
  117 */
  118     if (debug)
  119         printf("TLS initialization successful.\n");
  120     
  121 }
  122 
  123 void
  124 tls_auth(struct user_data *ud, int data, char *ucertspath, char *cafile)
  125 {
  126     SSL *ssl;
  127     char fn[NI_MAXHOST];
  128 
  129 #ifdef WIN32
  130     char sep = '\\';
  131 #else
  132     char sep = '/';
  133 #endif
  134 
  135     if (!data) {
  136         if ((ud->ssl_ctx = SSL_CTX_new(SSLv23_method())) == NULL) {
  137             printf("SSL_CTX_new() %s\n",(char *)ERR_error_string(ERR_get_error(), NULL));
  138             exit(1);
  139         }
  140         if (cafile[0] != '\0') { // CA verifications. 
  141             if (SSL_CTX_load_verify_locations(ud->ssl_ctx, cafile, NULL) != 1)
  142                 sys_err("could not load certificates from CA file.");
  143             else if (debug)
  144                 printf("Loaded CA file.\n");
  145         }
  146         SSL_CTX_set_options(ud->ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
  147         SSL_CTX_set_default_verify_paths(ud->ssl_ctx);
  148         
  149         if (ucertspath[0] != '\0') { /* Try to load user certificate chain */
  150             if (ucertspath[strlen(ucertspath)] == sep)
  151                 snprintf(fn, sizeof(fn), "%s%s.pem",ucertspath, ud->serv_dns.hostname);
  152             else
  153                 snprintf(fn, sizeof(fn), "%s%c%s.pem",ucertspath, sep, ud->serv_dns.hostname);
  154             if (SSL_CTX_use_certificate_chain_file(ud->ssl_ctx, fn) != 1) {
  155                 if (debug)
  156                     printf("failed to load %s\n", fn);
  157             } else {
  158                 if (debug)
  159                     printf("loaded %s\n", fn);
  160             }
  161         }
  162     }
  163 
  164     ssl = SSL_new(ud->ssl_ctx);
  165 
  166     if (ssl == NULL) {
  167             printf("SSL_new() %s\r\n",(char *)ERR_error_string(ERR_get_error(), NULL));
  168             exit(1);
  169     }
  170     
  171     if (data)
  172         ud->ssl_data = ssl;
  173     else
  174         ud->ssl_ctrl = ssl;
  175     if (debug)
  176         printf("tls_auth: ciphers: %s\n", cfg_tlsciphers);
  177 
  178     SSL_set_cipher_list(ssl, cfg_tlsciphers);
  179     
  180     /* if (sec_mode >= 3)
  181         SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL); */
  182     
  183     if (data) {
  184         if (SSL_set_fd(ssl, ud->serv_data_fd) != 1)
  185             printf("SSL_set_fd_error\n");
  186         if (ud->ssl_sess) { /* There is a cached SSL session */
  187             SSL_set_session(ssl, ud->ssl_sess);
  188             SSL_SESSION_free(ud->ssl_sess);
  189             ud->ssl_sess = NULL;
  190         }
  191     } else {
  192         if (SSL_set_fd(ssl, ud->serv_fd) != 1)
  193             printf("SSL_set_fd_error\n");
  194     }
  195 
  196     SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  197     tls_auth_cont(ud, data);
  198 }
  199 
  200 int tls_cert(struct user_data *ud, int data) /* save new key or verify saved key */
  201 {
  202     X509    *x509_peer, *x509_stored;
  203     FILE    *fp;
  204     char    filename[1024];
  205     int     cert_ok;
  206     
  207     cert_ok = 0;
  208     x509_stored = NULL;
  209 
  210     if (debug)
  211         printf("tls_cert\n");
  212 
  213     if ((x509_peer = SSL_get_peer_certificate((data) ? ud->ssl_data : ud->ssl_ctrl)) == NULL)
  214         return 0; /* SSL_get_peer* can only be NULL on  'anonymous DH connections' so shouldn't happen. */ 
  215     
  216     snprintf(filename, sizeof(filename), "%s-%s.pem", (data && !ud->epsv) ? ud->serv_data_host : ud->serv_dns.hostname,
  217         (data) ? "data" : "ctrl");
  218     if ( (fp = fopen(filename, "r")) == NULL) { /* key doesn't exist, store it */
  219         if (debug)
  220             printf("key %s doesn't exist, store it\n", filename);
  221         if (ud->sec_level == 2) { /* don't add new certs */
  222             X509_free(x509_peer);
  223             return 0;
  224         }
  225         if ( (fp = fopen(filename, "w")) == NULL) {
  226             X509_free(x509_peer);
  227             sys_err(filename);
  228          } else {
  229             PEM_write_X509(fp, x509_peer);
  230             cert_ok = 1;
  231         }
  232     } else { /* KEY already exists, verify it */
  233         if (debug)
  234             printf("key %s exists, verifying it\n", filename);
  235         if((x509_stored = PEM_read_X509(fp, NULL, 0, NULL)) == NULL)
  236             sys_err("can't read certificate");
  237         if (X509_cmp(x509_peer, x509_stored) == 0)
  238             cert_ok = 1;
  239         else {
  240             if (debug)
  241                 printf("X509_cmp failed\n");
  242         }
  243 
  244         if (debug && cert_ok)
  245             printf("verified cert ok\n");
  246     }
  247 
  248     fclose(fp);
  249     
  250     X509_free(x509_peer);
  251     if (x509_stored != NULL)
  252         X509_free(x509_stored);
  253     return cert_ok;
  254 }
  255 
  256 long tls_cert2(struct user_data *ud, int data) /* save new key or verify saved key */
  257 {
  258     X509                *x509_peer;
  259     X509_NAME           *x509_subj;
  260     X509_EXTENSION      *x509_ext;
  261     X509V3_EXT_METHOD   *x509_meth;
  262     int                 ok, extcount, i, j;
  263     char                *extstr;
  264     SSL                 *ssl;
  265 #if (OPENSSL_VERSION_NUMBER > 0x00908000L)
  266     unsigned char const     *data1;
  267 #else
  268     unsigned char   *data1;
  269 #endif
  270     char                data2[256];
  271     STACK_OF(CONF_VALUE) *val;
  272     CONF_VALUE          *nval;
  273     void                *ext_str = NULL;
  274     int                 subjectaltname;
  275 
  276     ok = subjectaltname = 0;
  277     ssl = (data) ? ud->ssl_data : ud->ssl_ctrl;
  278 
  279     if (debug)
  280         printf("tls_cert2\n");
  281     
  282     if ((x509_peer = SSL_get_peer_certificate(ssl)) == NULL)
  283         return X509_V_ERR_APPLICATION_VERIFICATION; /* SSL_get_peer* can only be NULL on  'anonymous DH connections' so shouldn't happen. */
  284 
  285     if (ud->sec_level == 3) {
  286         X509_free(x509_peer);
  287         return SSL_get_verify_result(ssl);
  288     }
  289     
  290     if ((extcount = X509_get_ext_count(x509_peer)) > 0) {
  291         if (debug) printf("extcount = %d\n", extcount);
  292         for (i = 0; i < extcount; i++) {
  293             x509_ext = X509_get_ext(x509_peer, i);
  294             extstr = (char*)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(x509_ext)));
  295             if (debug) printf("extstr = %s\n", extstr);
  296             if (!strcmp(extstr, "subjectAltName")) {
  297                 subjectaltname = 1;
  298                 if  (!(x509_meth = X509V3_EXT_get(x509_ext)))
  299                     break;
  300                 data1 = x509_ext->value->data;
  301 #if (OPENSSL_VERSION_NUMBER > 0x00907000L)     
  302                 if (x509_meth->it)
  303                     ext_str = ASN1_item_d2i(NULL, &data1, x509_ext->value->length, ASN1_ITEM_ptr(x509_meth->it));
  304                 else
  305                     ext_str = x509_meth->d2i(NULL, &data1, x509_ext->value->length);
  306 #else
  307                 ext_str = x509_meth->d2i(NULL, &data1, x509_ext->value->length);
  308 #endif
  309                 val = x509_meth->i2v(x509_meth, ext_str, NULL);
  310                 for (j = 0; j < sk_CONF_VALUE_num(val); j++) {
  311                         nval = sk_CONF_VALUE_value(val, j);
  312                         if (debug)
  313                             printf("X509 extension : %s - %s\n", nval->name, nval->value);
  314                         if (!strcmp(nval->name, "DNS") && !strcasecmp(nval->value, ud->serv_host)) {
  315                             ok = 1;
  316                             break;
  317                         } else if (!strcmp(nval->name, "IP Address") &&
  318                             ( (data == 0 && !strcmp(nval->value, ud->serv_dns.hostname)) ||
  319                               (data == 1 && !strcmp(nval->value, ud->serv_data_host)) ) ) {
  320                             ok = 1;
  321                             break;
  322                         }
  323                 }
  324             }
  325             if (ok) break;
  326         }
  327   }
  328 
  329   if (!ok && (x509_subj = X509_get_subject_name(x509_peer)) && X509_NAME_get_text_by_NID(x509_subj, NID_commonName, data2, sizeof(data2)) > 0) {
  330     data2[255] = 0;
  331     if ((strcasecmp(data2, ud->serv_host) != 0) || subjectaltname) {
  332         X509_free(x509_peer);
  333         return X509_V_ERR_APPLICATION_VERIFICATION;
  334     }
  335   }
  336   X509_free(x509_peer);
  337     return SSL_get_verify_result(ssl);
  338 }
  339 
  340 void
  341 tls_auth_cont(struct user_data *ud, int data)
  342 {
  343     int status, sslerr, cert_ok;
  344     SSL_CIPHER *cipher;
  345     char cipher_info[128];
  346     SSL *ssl;
  347 
  348     if (debug)
  349         printf("tls_auth_cont\n");
  350     ssl = (data) ? ud->ssl_data : ud->ssl_ctrl;
  351     
  352     if (ssl == NULL) printf("SSL == NULL!\n");
  353 
  354     status = SSL_connect(ssl);
  355     sslerr = SSL_get_error(ssl, status);
  356     if (data)
  357         ud->ssl_data_fd_mode = TLS_NONE;
  358     else
  359         ud->ssl_ctrl_fd_mode = TLS_NONE;
  360     
  361   /*    if ((data) && (status == 1)) {
  362         status = -1; sslerr = 1; } */
  363 
  364     if (status == 1) { /* The TLS/SSL handshake was successfully completed */
  365         cipher = SSL_get_current_cipher(ssl);
  366         SSL_CIPHER_description(cipher, cipher_info, sizeof(cipher_info));
  367         if (debug)
  368             printf("cipher %s, sec_level %d\n", cipher_info, ud->sec_level);
  369         cert_ok = (ud->sec_level == 1 || ud->sec_level == 2) ? tls_cert(ud, data) : (ud->sec_level >= 3) ? tls_cert2(ud, data) == X509_V_OK : 1;
  370         if (debug)
  371             printf("cert_ok = %d, data = %d\n", cert_ok, data);
  372 
  373         if (data) {
  374             ud->tls_status |= TLS_DATA;
  375             ud->data_connected = CONN_DATA_OK;
  376         } else {
  377             ud->serv_status = SERV_TLS_OK;
  378             ud->tls_status |= TLS_CTRL;
  379             print_to_serv(ud, "PBSZ 0\r\n");
  380             if (debug)
  381                 printf("printed pbsz\n");
  382         }
  383         if (!cert_ok) {
  384             if (!data) {
  385                 ud->serv_status = SERV_FLOW;
  386                 print_to_ud(ud, "530 TLSWrap certificate verification failed, disconnecting.\r\n");
  387                 print_to_serv(ud, "QUIT\r\n");
  388             } else {
  389                 print_to_ud(ud, "425 TLSWrap data certificate verification failed.\r\n");
  390                 SSL_clear(ud->ssl_data); /* Prevent reuse */
  391                 data_close(ud); 
  392             }
  393             if (debug)
  394                 printf("printed that certificate verification failed.\n");
  395             //user_close(ud);
  396         }
  397     } else {
  398         switch (sslerr) {
  399             case SSL_ERROR_WANT_READ:
  400                 if (debug)
  401                     printf("setting TLS_READ\n");
  402                 if (data)
  403                     ud->ssl_data_fd_mode = TLS_READ;
  404                 else
  405                     ud->ssl_ctrl_fd_mode = TLS_READ;
  406                 break;
  407             case SSL_ERROR_WANT_WRITE:
  408                 if (debug)
  409                     printf("setting TLS_WRITE\n");
  410                 if (data)
  411                     ud->ssl_data_fd_mode = TLS_WRITE;
  412                 else
  413                     ud->ssl_ctrl_fd_mode = TLS_WRITE;
  414                 break;
  415             case SSL_ERROR_SSL:
  416             case SSL_ERROR_SYSCALL: // assorted I/O error
  417                 if (debug)
  418                     printf("tls_auth_cont got SSL_ERROR_SSL or SSL_ERROR_SYSCALL\n");
  419                 if (!data) {
  420                     ud->serv_status = SERV_NONE;
  421                     print_to_ud(ud, "530 TLSWrap SSL/TLS connection to server failed.\r\n");
  422                     ud->connected = CONN_NO;
  423                 } else {
  424                     /* ud->serv_data_close = CLOSE_READ;
  425                       ud->user_data_close = CLOSE_READ; */
  426                     print_to_ud(ud, "230 TLSWrap SSL/TLS DATA connection to server failed.\r\n");
  427                     SSL_clear(ssl);
  428                     data_close(ud);
  429                 }
  430                 break;
  431             default:
  432                 if (debug)
  433                     printf("tls_auth_cont failed (%d)\n", sslerr);
  434                 if (sslerr)
  435                     perror("tls_auth_cont");
  436                 if (data) {
  437                     SSL_clear(ud->ssl_data);
  438                     data_close(ud);
  439                 }
  440         }
  441     }
  442 }
  443 
  444 int
  445 tls_write(struct user_data *ud, const void *buf, int num, int data)
  446 {
  447     SSL     *ssl;
  448     int status, sslerr;
  449 
  450     ssl = (data) ? ud->ssl_data : ud->ssl_ctrl;
  451 
  452     status = SSL_write(ssl, buf, num);
  453     sslerr = SSL_get_error(ssl, status);
  454 
  455     if (status == -1) {
  456         if (data)
  457             ud->ssl_data_func = TLS_WRITE;
  458         else
  459             ud->ssl_ctrl_func = TLS_WRITE;
  460         switch (sslerr) {
  461             case SSL_ERROR_WANT_READ:
  462                 if (data)
  463                     ud->ssl_data_fd_mode = TLS_READ;
  464                 else
  465                     ud->ssl_ctrl_fd_mode = TLS_READ;
  466                 break;
  467             case SSL_ERROR_WANT_WRITE:
  468                 if (data)
  469                     ud->ssl_data_fd_mode = TLS_WRITE;
  470                 else
  471                     ud->ssl_ctrl_fd_mode = TLS_WRITE;
  472                 break;
  473             default:
  474                 if (debug)
  475                     printf("tls_write_error\n");
  476                 return -1;
  477         }
  478     } else {
  479         if (data)
  480             ud->ssl_data_fd_mode = TLS_NONE;
  481         else
  482             ud->ssl_ctrl_fd_mode = TLS_NONE;
  483     }
  484 
  485     return status;
  486 }
  487 
  488 int
  489 tls_read(struct user_data *ud, void *buf, int num, int data)
  490 {
  491     SSL     *ssl;
  492     int     status, sslerr;
  493 
  494     ssl = (data) ? ud->ssl_data : ud->ssl_ctrl;
  495 
  496     status = SSL_read(ssl, buf, num);
  497     sslerr = SSL_get_error(ssl, status);
  498 
  499     if (status == -1) {
  500         if (data)
  501             ud->ssl_data_func = TLS_READ;
  502         else
  503             ud->ssl_ctrl_func = TLS_READ;
  504         switch (sslerr) {
  505             case SSL_ERROR_WANT_READ:
  506                 if (data)
  507                     ud->ssl_data_fd_mode = TLS_READ;
  508                 else
  509                     ud->ssl_ctrl_fd_mode = TLS_READ;
  510                 break;
  511             case SSL_ERROR_WANT_WRITE:
  512                 if (data)
  513                     ud->ssl_data_fd_mode = TLS_WRITE;
  514                 else
  515                     ud->ssl_ctrl_fd_mode = TLS_WRITE;
  516                 break;
  517             default:
  518                 if (debug)
  519                     printf("tls_read_error\n");
  520                 return -2;
  521         }
  522     } else {
  523         if (data)
  524             ud->ssl_data_fd_mode = TLS_NONE;
  525         else
  526             ud->ssl_ctrl_fd_mode = TLS_NONE;
  527     }
  528     
  529     return status;
  530 }