ShellBanner
System:Linux MiraNet 3.0.0-14-generic-pae #23-Ubuntu SMP Mon Nov 21 22:07:10 UTC 2011 i686
Software:Apache. PHP/5.3.6-13ubuntu3.10
ID:uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
Safe Mode:OFF
Open_Basedir:OFF
Freespace:27.57 GB of 70.42 GB (39.16%)
MySQL: ON MSSQL: OFF Oracle: OFF PostgreSQL: OFF Curl: OFF Sockets: ON Fetch: OFF Wget: ON Perl: ON
Disabled Functions: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,

/ usr/ src/ courier-0.66.1/ tcpd/ - drwxrwxrwx

Directory:
Viewing file:     libcouriertls.c (29.13 KB)      -rw-rw-rw-
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
** Copyright 2000-2009 Double Precision, Inc.
** See COPYING for distribution information.
*/
#include    "config.h"
#include    "argparse.h"
#include    "spipe.h"
#define COURIERTCPD_EXPOSE_OPENSSL 1
#include    "libcouriertls.h"
#include    <openssl/rand.h>
#include    <openssl/x509.h>
#include    "tlscache.h"
#include    "rfc1035/rfc1035.h"
#include    "soxwrap/soxwrap.h"
#include    "random128/random128.h"
#ifdef  getc
#undef  getc
#endif
#include    <stdio.h>
#include    <string.h>
#include    <stdlib.h>
#include    <ctype.h>
#include    <netdb.h>
#if HAVE_DIRENT_H
#include <dirent.h>
#define NAMLEN(dirent) strlen((dirent)->d_name)
#else
#define dirent direct
#define NAMLEN(dirent) (dirent)->d_namlen
#if HAVE_SYS_NDIR_H
#include <sys/ndir.h>
#endif
#if HAVE_SYS_DIR_H
#include <sys/dir.h>
#endif
#if HAVE_NDIR_H
#include <ndir.h>
#endif
#endif
#if    HAVE_UNISTD_H
#include    <unistd.h>
#endif
#if    HAVE_FCNTL_H
#include    <fcntl.h>
#endif
#include    <errno.h>
#if    HAVE_SYS_TYPES_H
#include    <sys/types.h>
#endif
#if    HAVE_SYS_STAT_H
#include    <sys/stat.h>
#endif
#include    <sys/socket.h>
#include    <arpa/inet.h>

#include    <sys/time.h>

/***** TODO *****/

/* #define TLSCACHEDEBUG */

static const char *safe_getenv(const struct tls_info *info, const char *n)
{
    const char *v=(*info->getconfigvar)(n, info->app_data);

    if (!v)    v="";
    return (v);
}

static int get_peer_verify_level(const struct tls_info *info)
{
    int peer_verify_level=SSL_VERIFY_PEER;
        /* SSL_VERIFY_NONE */
        /* SSL_VERIFY_PEER */
        /* SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */
    const char *s=safe_getenv(info, "TLS_VERIFYPEER");

    if (info->peer_verify_domain)
        return SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;

    switch (*s)    {
    case 'n':
    case 'N':        /* NONE */
        peer_verify_level=SSL_VERIFY_NONE;
        break;
    case 'p':
    case 'P':        /* PEER */
        peer_verify_level=SSL_VERIFY_PEER;
        break;
    case 'r':
    case 'R':        /* REQUIREPEER */
        peer_verify_level=
            SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
        break;
    }
    return (peer_verify_level);
}

static int ssl_verify_callback(int goodcert, X509_STORE_CTX *x509)
{
    SSL *ssl=
        X509_STORE_CTX_get_ex_data(x509,
                       SSL_get_ex_data_X509_STORE_CTX_idx()
                       );
    struct tls_info *info=SSL_get_app_data(ssl);

    if (info->peer_verify_domain || get_peer_verify_level(info))
    {
        if (!goodcert)
            return (0);

        info->certificate_verified=1;
    }

    return (1);
}

static int verifypeer(const struct tls_info *info, SSL *ssl)
{
    X509 *x=NULL;
    X509_NAME *subj=NULL;
    int nentries, j;
    char domain[256];
    char *p;
    char errmsg[1000];

    if (!info->peer_verify_domain)
        return (1);

    if (info->isserver)
    {
        x=SSL_get_peer_certificate(ssl);

        if (x)
            subj=X509_get_subject_name(x);
    }
    else
    {
        STACK_OF(X509) *peer_cert_chain=SSL_get_peer_cert_chain(ssl);

        if (peer_cert_chain && peer_cert_chain->stack.num > 0)
        {
            X509 *xx=(X509 *)peer_cert_chain->stack.data[0];

            if (xx)
                subj=X509_get_subject_name(xx);
        }
    }

    
    nentries=0;
    if (subj)
        nentries=X509_NAME_entry_count(subj);

    domain[0]=0;
    for (j=0; j<nentries; j++)
    {
        const char *obj_name;
        X509_NAME_ENTRY *e;
        ASN1_OBJECT *o;
        ASN1_STRING *d;

        int dlen;
        unsigned char *ddata;

        e=X509_NAME_get_entry(subj, j);
        if (!e)
            continue;

        o=X509_NAME_ENTRY_get_object(e);
        d=X509_NAME_ENTRY_get_data(e);

        if (!o || !d)
            continue;

        obj_name=OBJ_nid2sn(OBJ_obj2nid(o));

        dlen=ASN1_STRING_length(d);
        ddata=ASN1_STRING_data(d);

        if (strcasecmp(obj_name, "CN") == 0)
        {
            if (dlen >= sizeof(domain)-1)
                dlen=sizeof(domain)-1;

            memcpy(domain, ddata, dlen);
            domain[dlen]=0;
        }
    }

    if (x)
        X509_free(x);
    p=domain;

    if (*p == '*')
    {
        int    pl, l;

        pl=strlen(++p);
        l=strlen(info->peer_verify_domain);

        if (*p == '.' && pl <= l &&
            strcasecmp(info->peer_verify_domain+l-pl, p) == 0)
            return (1);
    }
    else if (strcasecmp(info->peer_verify_domain, p) == 0)
        return (1);

    strcpy(errmsg, "couriertls: Mismatched SSL certificate: CN=");
    strcat(errmsg, domain);
    strcat(errmsg, " (expected ");
    strncat(errmsg, info->peer_verify_domain, 256);
    strcat(errmsg, ")");
    (*info->tls_err_msg)(errmsg, info->app_data);
    return (0);
}

#ifndef NO_RSA

static RSA *rsa_callback(SSL *s, int export, int keylength)
{
    return (RSA_generate_key(keylength,RSA_F4,NULL,NULL));
}

#endif

static void nonsslerror(const struct tls_info *info, const char *pfix)
{
    char errmsg[256];

    strcpy(errmsg, "couriertls: ");
    strncat(errmsg, pfix, 200);
    strcat(errmsg, ": ");
    strncat(errmsg, strerror(errno), 255 - strlen(errmsg));

    (*info->tls_err_msg)(errmsg, info->app_data);
}

static void sslerror(const struct tls_info *info, const char *pfix, int rc)
{
    char errmsg[256];
    char errmsgbuf2[300];
    int errnum=ERR_get_error();

    if (errnum == 0)
    {
        if (rc == 0)
        {
            (*info->tls_err_msg)("DEBUG: Unexpected SSL connection shutdown.",
                         info->app_data);
            return;
        }

        nonsslerror(info, pfix);
        return;
    }

    ERR_error_string_n(errnum, errmsg, sizeof(errmsg)-1);

    errmsg[sizeof(errmsg)-1]=0;

    strcpy(errmsgbuf2, "couriertls: ");
    strncat(errmsgbuf2, pfix, 200);
    strcat(errmsgbuf2, ": ");
    strncat(errmsgbuf2, errmsg, 299 - strlen(errmsgbuf2));

    (*info->tls_err_msg)(errmsgbuf2, info->app_data);
}

static void init_session_cache(struct tls_info *, SSL_CTX *);

static int process_rsacertfile(SSL_CTX *ctx, const char *filename)
{
#ifndef    NO_RSA

    const struct tls_info *info=SSL_CTX_get_app_data(ctx);

    SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);

    if(!SSL_CTX_use_certificate_chain_file(ctx, filename))
    {
        sslerror(info, filename, -1);
        return (0);
    }

    if(!SSL_CTX_use_RSAPrivateKey_file(ctx, filename, SSL_FILETYPE_PEM))
    {
        sslerror(info, filename, -1);
        return (0);
    }
#endif
    return (1);
}


static int process_dhcertfile(SSL_CTX *ctx, const char *filename)
{
#ifndef    NO_DH

    const struct tls_info *info=SSL_CTX_get_app_data(ctx);
    BIO    *bio;
    DH    *dh;
    int    cert_done=0;

    if(!SSL_CTX_use_certificate_chain_file(ctx, filename))
    {
        sslerror(info, filename, -1);
        return (0);
    }

    if ((bio=BIO_new_file(filename, "r")) != 0)
    {
        if ((dh=PEM_read_bio_DHparams(bio, NULL, NULL, NULL)) != 0)
        {
            SSL_CTX_set_tmp_dh(ctx, dh);
            cert_done=1;
            DH_free(dh);
        }
        else
            sslerror(info, filename, -1);
        BIO_free(bio);
    }
    else
        sslerror(info, filename, -1);

    if (!cert_done)
    {
        (*info->tls_err_msg)("couriertls: DH init failed!",
                     info->app_data);

        return (0);
    }

    if(!SSL_CTX_use_PrivateKey_file(ctx, filename, SSL_FILETYPE_PEM))
    {
        sslerror(info, filename, -1);
        return (0);
    }
#endif
    return (1);
}

static int process_certfile(SSL_CTX *ctx, const char *certfile, const char *ip,
                int (*func)(SSL_CTX *, const char *))
{
    if (ip && *ip)
    {
        char *test_file;

        if (strncmp(ip, "::ffff:", 7) == 0 && strchr(ip, '.'))
            return (process_certfile(ctx, certfile, ip+7, func));

        test_file= malloc(strlen(certfile)+strlen(ip)+2);

        strcpy(test_file, certfile);
        strcat(test_file, ".");
        strcat(test_file, ip);

        if (access(test_file, R_OK) == 0)
        {
            int rc= (*func)(ctx, test_file);

            free(test_file);
            return rc;
        }
        free(test_file);
    }

    return (*func)(ctx, certfile);
}

static int client_cert_cb(ssl_handle ssl, X509 **x509, EVP_PKEY **pkey)
{
    struct tls_info *info=(struct tls_info *)SSL_get_app_data(ssl);
    int i;
    const char *pem_cert;
    size_t pem_cert_size;
    STACK_OF(X509_NAME) *client_cas;
    int cert_num=0;
    int rc;

    if (info->getpemclientcert4ca == NULL)
        return 0;

    rc=0;
    client_cas=SSL_get_client_CA_list(ssl);

    if (info->loadpemclientcert4ca)
        (*info->loadpemclientcert4ca)(info->app_data);

    for (cert_num=0; (*info->getpemclientcert4ca)(cert_num, &pem_cert,
                              &pem_cert_size,
                              info->app_data);
         ++cert_num)
    {
        BIO *certbio;
        int err;
        X509 *x;

        ERR_clear_error();

        certbio=BIO_new_mem_buf((void *)pem_cert, pem_cert_size);

        if (!certbio)
        {
            rc= -1;
            break;
        }

        x=PEM_read_bio_X509(certbio, x509, NULL, NULL);

        if (!x)
        {
            BIO_free(certbio);
            continue;
        }

        for (i=0; client_cas && i<client_cas->stack.num; i++)
        {
            X509_NAME *cert=(X509_NAME *)client_cas->stack.data[i];

            if (X509_NAME_cmp(cert,
                      x->cert_info->issuer) == 0)
                break;
        }

        if (!client_cas || i >= client_cas->stack.num)
        {
            BIO_free(certbio);
            continue;
        }

        while ((x=PEM_read_bio_X509(certbio, NULL,
                        NULL, 0)) != NULL)
        {
            if (SSL_CTX_add_extra_chain_cert(SSL_get_SSL_CTX(ssl),
                             x)
                != 1)
            {
                X509_free(x);
                rc= -1;
                break;
            }
        }

        err = ERR_peek_last_error();
        if (rc || ERR_GET_LIB(err) != ERR_LIB_PEM ||
            ERR_GET_REASON(err) != PEM_R_NO_START_LINE)
        {
            BIO_free(certbio);
            continue;
        }
        BIO_free(certbio);

        ERR_clear_error();

        certbio=BIO_new_mem_buf((void *)pem_cert, pem_cert_size);

        if (!certbio)
        {
            rc= -1;
            break;
        }

        if (!PEM_read_bio_PrivateKey(certbio, pkey, NULL, NULL))
        {
            BIO_free(certbio);
            continue;
        }

        BIO_free(certbio);
        rc=1;
        break;
    }
    ERR_clear_error();
    (*info->releasepemclientcert4ca)(info->app_data);
    return rc;
}

SSL_CTX *tls_create(int isserver, const struct tls_info *info)
{
    SSL_CTX *ctx;
    const char *protocol=safe_getenv(info, "TLS_PROTOCOL");
    const char *ssl_cipher_list=safe_getenv(info, "TLS_CIPHER_LIST");
    int session_timeout=atoi(safe_getenv(info, "TLS_TIMEOUT"));
    const char *dhcertfile=safe_getenv(info, "TLS_DHCERTFILE");
    const char *certfile=safe_getenv(info, "TLS_CERTFILE");
    const char *s;
    struct stat stat_buf;
    const char *peer_cert_dir=NULL;
    const char *peer_cert_file=NULL;
    int n;
    struct tls_info *info_copy;

    if (!*ssl_cipher_list)
        ssl_cipher_list=NULL;

    if (!*dhcertfile)
        dhcertfile=NULL;

    if (!*certfile)
        certfile=NULL;

    s=safe_getenv(info, "TLS_TRUSTCERTS");
    if (s && stat(s, &stat_buf) == 0)
    {
        if (S_ISDIR(stat_buf.st_mode))
            peer_cert_dir=s;
        else
            peer_cert_file=s;
    }
    else if (info->peer_verify_domain)
    {
        errno=ENOENT;
        nonsslerror(info, "TLS_TRUSTCERTS not set");
        return (NULL);
    }

    {
        static int first=1;

        if (first)
        {
            first=0;
            SSL_load_error_strings();
            SSLeay_add_ssl_algorithms();

            while (RAND_status() != 1)
            {
                const char *p=random128();
                size_t l=strlen(p);

                RAND_add(p, l, l/16);
            }
        }
    }


    info_copy=malloc(sizeof(struct tls_info));

    if (info_copy == NULL)
    {
        nonsslerror(info, "malloc");
        return (NULL);
    }

    memcpy(info_copy, info, sizeof(*info_copy));
    info_copy->isserver=isserver;
    info_copy->certificate_verified=0;

    if (!protocol || !*protocol)
        protocol="SSL23";

    ctx=SSL_CTX_new(protocol && strcmp(protocol, "SSL3") == 0
            ? SSLv3_method():
            protocol && strcmp(protocol, "SSL23") == 0
            ? SSLv23_method():
            TLSv1_method());

    if (!ctx)
    {
        free(info_copy);
        nonsslerror(info, "SSL_CTX_NEW");
        return (0);
    }
    SSL_CTX_set_app_data(ctx, info_copy);
    SSL_CTX_set_options(ctx, SSL_OP_ALL);

    if (!ssl_cipher_list)
        ssl_cipher_list="SSLv3:TLSv1:HIGH:!LOW:!MEDIUM:!EXP:!NULL:!aNULL@STRENGTH";

    SSL_CTX_set_cipher_list(ctx, ssl_cipher_list);
    SSL_CTX_set_timeout(ctx, session_timeout);

    info_copy->tlscache=NULL;
    init_session_cache(info_copy, ctx);


    s = safe_getenv(info, "TCPLOCALIP");

    if (certfile && !process_certfile(ctx, certfile, s,
                      process_rsacertfile))
    {
        tls_destroy(ctx);
        return (NULL);
    }

    if (dhcertfile && !process_certfile(ctx, dhcertfile, s,
                        process_dhcertfile))
    {
        tls_destroy(ctx);
        return (NULL);
    }

    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);

    n=atoi(safe_getenv(info, "TLS_INTCACHESIZE"));

    if (n > 0)
        SSL_CTX_sess_set_cache_size(ctx, n);

    if (peer_cert_dir || peer_cert_file)
    {
        if ((!SSL_CTX_set_default_verify_paths(ctx))
            || (!SSL_CTX_load_verify_locations(ctx, peer_cert_file,
                peer_cert_dir)))
        {
            sslerror(info, peer_cert_file ?
                 peer_cert_file:peer_cert_dir, -1);
            tls_destroy(ctx);
            return (0);
        }

        if (isserver && peer_cert_file)
        {
            SSL_CTX_set_client_CA_list(ctx,
                           SSL_load_client_CA_file
                           (peer_cert_file));
        }

        if (isserver && peer_cert_dir)
        {
            DIR *dirp;
            struct dirent *de;
            X509 *x;

            dirp=opendir(peer_cert_dir);
            while (dirp && (de=readdir(dirp)) != NULL)
            {
                const char *p;
                char *q;
                FILE *fp;

                p=strrchr(de->d_name, '.');
                if (!p || !p[1])
                    continue;
                while (*++p)
                {
                    if (strchr("0123456789", *p) == NULL)
                        break;
                }
                if (*p)
                    continue;

                q=malloc(strlen(peer_cert_dir)
                     +strlen(de->d_name) + 4);
                if (!q)
                {
                    nonsslerror(info, "malloc");
                    exit(1);
                }

                strcat(strcat(strcpy(q, peer_cert_dir),
                          "/"), de->d_name);

                fp=fopen(q, "r");
                if (!fp)
                {
                    nonsslerror(info, q);
                    exit(1);
                }
                free(q);

                while ((x=PEM_read_X509(fp, NULL, NULL, NULL)))
                {
                    SSL_CTX_add_client_CA(ctx,x);
                    X509_free(x);
                }
                fclose(fp);
            }
            if (dirp)
                closedir(dirp);
                }
    }
    SSL_CTX_set_verify(ctx, get_peer_verify_level(info),
               ssl_verify_callback);
    if (!isserver)
        SSL_CTX_set_client_cert_cb(ctx, client_cert_cb);
    return (ctx);
}

void tls_destroy(SSL_CTX *ctx)
{
    struct tls_info *info=SSL_CTX_get_app_data(ctx);

    SSL_CTX_flush_sessions(ctx, 0); /* OpenSSL bug, 2002-08-07 */

    SSL_CTX_free(ctx);

    if (info->tlscache)
    {
        tls_cache_close(info->tlscache);
        info->tlscache=NULL;
    }
    free(info);
}

static int cache_add(SSL *ssl, SSL_SESSION *sess);

static SSL_SESSION *cache_get(SSL *ssl, unsigned char *id, int id_len,
                  int *copyflag);
static void cache_del(SSL_CTX *ctx, SSL_SESSION *ssl);

static void init_session_cache(struct tls_info *info, SSL_CTX *ctx)
{
    const char *filename=safe_getenv(info, "TLS_CACHEFILE");
    const char *cachesize=safe_getenv(info, "TLS_CACHESIZE");
    off_t cachesize_l;

    if (!filename || !*filename)
    {
        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
        return;
    }

    if (info->tlscache == NULL)
    {
        cachesize_l= cachesize ? (off_t)atol(cachesize):0;

        if (cachesize_l <= 0)
            cachesize_l=512L * 1024;
        if ((info->tlscache=tls_cache_open(filename, cachesize_l))
            == NULL)
        {
            nonsslerror(info, filename);
            return;
        }
    }

        SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
    SSL_CTX_sess_set_new_cb(ctx, cache_add);
    SSL_CTX_sess_set_get_cb(ctx, cache_get);
    SSL_CTX_sess_set_remove_cb(ctx, cache_del);
}

static int cache_add(SSL *ssl, SSL_SESSION *sess)
{
    struct tls_info *info=SSL_get_app_data(ssl);
    unsigned char buffer[BUFSIZ];
    unsigned char *ucp;
    time_t timeout= (time_t)SSL_SESSION_get_time(sess)
        + SSL_SESSION_get_timeout(sess);
    void *session_id=(void *)sess->session_id;
    size_t session_id_len=sess->session_id_length;
    size_t sess_len=i2d_SSL_SESSION(sess, NULL);

    if (sizeof(timeout) + sizeof(session_id_len) + session_id_len +
        sess_len > sizeof(buffer))
    {
        fprintf(stderr, "WARN: starttls.c: buffer not big enough to cache SSL_SESSION\n");
        return (0);    /* Too big */
    }

    memcpy(buffer, &timeout, sizeof(timeout));
    memcpy(buffer+sizeof(timeout), &session_id_len,
           sizeof(session_id_len));
    memcpy(buffer+sizeof(timeout)+sizeof(session_id_len),
           session_id, session_id_len);
    ucp=buffer+sizeof(timeout)+
        sizeof(session_id_len)+session_id_len;

    i2d_SSL_SESSION(sess, &ucp);
    if (tls_cache_add(info->tlscache, (char *)buffer,
              (size_t)(sizeof(timeout) +
                   sizeof(session_id_len) +
                   session_id_len + sess_len)))
        perror("ALERT: tls_cache_add: ");

#ifdef TLSCACHEDEBUG
    fprintf(stderr, "INFO: TLSCACHE: added\n");
#endif
    return 0;
}

struct walk_info {
    unsigned char *id;
    int id_len;
    int *copyflag;
    SSL_SESSION *ret;
    time_t now;
};

static int get_func(void *rec, size_t recsize,
            int *doupdate, void *arg);

static SSL_SESSION *cache_get(SSL *ssl, unsigned char *id, int id_len,
                  int *copyflag)
{
    const struct tls_info *info=SSL_get_app_data(ssl);
    struct walk_info wi;

    wi.id=id;
    wi.id_len=id_len;
    wi.copyflag=copyflag;
    wi.ret=NULL;
    time(&wi.now);
    if (tls_cache_walk(info->tlscache, get_func, &wi) < 0)
        perror("ALERT: tls_cache_walk: ");

#ifdef TLSCACHEDEBUG
    fprintf(stderr, "INFO: TLSCACHE: session %s\n",
        wi.ret ? "found":"not found");
#endif
    if (wi.ret)
        SSL_set_session_id_context(ssl, id, id_len);
    return wi.ret;
}

static int get_func(void *rec, size_t recsize,
            int *doupdate, void *arg)
{
    unsigned char *recp=(unsigned char *)rec;
    struct walk_info *wi=(struct walk_info *)arg;
    time_t timeout;
    size_t session_id_len;

    unsigned char *sess;

    if (recsize < sizeof(timeout)+sizeof(session_id_len))
        return (0);

    memcpy(&timeout, recp, sizeof(timeout));

    if (timeout <= wi->now)
        return (0);

    memcpy(&session_id_len, recp + sizeof(timeout),
           sizeof(session_id_len));

    if (session_id_len != (size_t)wi->id_len ||
        memcmp(recp + sizeof(timeout) + sizeof(session_id_len),
           wi->id, session_id_len))
        return (0);

    sess=recp + sizeof(timeout) + sizeof(session_id_len) + session_id_len;

    wi->ret=d2i_SSL_SESSION(NULL, (const unsigned char **)
                &sess, recsize - sizeof(timeout) -
                sizeof(session_id_len) - session_id_len);

    *wi->copyflag=0;
    return 1;
}

static int del_func(void *rec, size_t recsize,
            int *doupdate, void *arg);

static void cache_del(SSL_CTX *ctx, SSL_SESSION *sess)
{
    const struct tls_info *info=SSL_CTX_get_app_data(ctx);
    struct walk_info wi;

    wi.now=0;

    wi.id=(unsigned char *)sess->session_id;
    wi.id_len=sess->session_id_length;
    if (tls_cache_walk(info->tlscache, del_func, &wi) < 0)
        perror("ALERT: tls_cache_walk: ");
}

static int del_func(void *rec, size_t recsize,
            int *doupdate, void *arg)
{
    unsigned char *recp=(unsigned char *)rec;
    struct walk_info *wi=(struct walk_info *)arg;
    time_t timeout;
    size_t session_id_len;

    if (recsize < sizeof(timeout)+sizeof(session_id_len))
        return (0);

    memcpy(&timeout, recp, sizeof(timeout));

    if (timeout <= wi->now)
        return (0);

    memcpy(&session_id_len, recp + sizeof(timeout),
           sizeof(session_id_len));

    if (session_id_len != (size_t)wi->id_len ||
        memcmp(recp + sizeof(timeout) + sizeof(session_id_len),
           wi->id, session_id_len))
        return (0);

    timeout=0;
    memcpy(recp, &timeout, sizeof(timeout));
    *doupdate=1;
#ifdef TLSCACHEDEBUG
    fprintf(stderr, "INFO: TLSCACHE: deleted\n");
#endif
    return (1);
}


/* ----------------------------------------------------------------- */

SSL *tls_connect(SSL_CTX *ctx, int fd)
{
    struct tls_info *info=SSL_CTX_get_app_data(ctx);
    SSL *ssl;
    int rc;

    /*
    **  Initialize a tls_transfer_info object.
    */

    if (fcntl(fd, F_SETFL, O_NONBLOCK))
    {
        nonsslerror(info, "fcntl");
        return (NULL);
    }

#ifdef  SO_KEEPALIVE

    {
    int    dummy;

        dummy=1;

        if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
            (const char *)&dummy, sizeof(dummy)) < 0)
                {
                        nonsslerror(info, "setsockopt");
            return (NULL);
                }
    }
#endif

#ifdef  SO_LINGER
    {
    struct linger l;

        l.l_onoff=0;
        l.l_linger=0;

        if (setsockopt(fd, SOL_SOCKET, SO_LINGER,
            (const char *)&l, sizeof(l)) < 0)
        {
            nonsslerror(info, "setsockopt");
            return (NULL);
        }
    }
#endif

    if (!(ssl=SSL_new(ctx)))
    {
        sslerror(info, "SSL_new", -1);
        return (NULL);
    }

    SSL_set_app_data(ssl, info);

    SSL_set_fd(ssl, fd);
    info->accept_interrupted=0;
    info->connect_interrupted=0;

    if (info->isserver)
    {
        SSL_set_accept_state(ssl);
        if ((rc=SSL_accept(ssl)) > 0)
        {
            if (!verifypeer(info, ssl))
            {
                tls_disconnect(ssl, fd);
                return (NULL);
            }

            if (info->connect_callback != NULL &&
                !(*info->connect_callback)(ssl, info->app_data))
            {
                tls_disconnect(ssl, fd);
                return (NULL);
            }

            return ssl;
        }
        info->accept_interrupted=1;
    }
    else
    {
        SSL_set_connect_state(ssl);

        if ((rc=SSL_connect(ssl)) > 0)
        {
            if (!verifypeer(info, ssl))
            {
                tls_disconnect(ssl, fd);
                return (NULL);
            }

            if (info->connect_callback != NULL &&
                !(*info->connect_callback)(ssl, info->app_data))
            {
                tls_disconnect(ssl, fd);
                return (NULL);
            }
            return (ssl);
        }
        info->connect_interrupted=1;
    }

    switch (SSL_get_error(ssl, rc))    {
    case SSL_ERROR_WANT_WRITE:
    case SSL_ERROR_WANT_READ:
        break;
    default:
        sslerror(info, "connect", rc);
        tls_disconnect(ssl, fd);
        return NULL;
    }

    return (ssl);
}

void tls_disconnect(SSL *ssl, int fd)
{
    fcntl(fd, F_SETFL, 0);
    SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
    SSL_free(ssl);
    ERR_remove_state(0);
}

/* --------------------------------------- */

int    tls_transfer(struct tls_transfer_info *t, SSL *ssl, int fd,
             fd_set *r, fd_set *w)
{
    struct tls_info *info=SSL_get_app_data(ssl);
    int n;

    if (info->connect_interrupted)
    {
        n=SSL_connect(ssl);

        switch (SSL_get_error(ssl, n))    {
        case SSL_ERROR_NONE:
            info->connect_interrupted=0;
            break;
        case SSL_ERROR_WANT_WRITE:
            FD_SET(fd, w);
            return (1);
        case SSL_ERROR_WANT_READ:
            FD_SET(fd, r);
            return (1);
        default:
            info->connect_interrupted=0;
            t->shutdown=1;
            sslerror(info, "connect", n);
            return (-1);
        }

        if (!verifypeer(info, ssl))
        {
            info->connect_interrupted=0;
            t->shutdown=1;
            return (-1);
        }
        if (info->connect_callback != NULL &&
            !(*info->connect_callback)(ssl, info->app_data))
        {
            info->connect_interrupted=0;
            t->shutdown=1;
            return (-1);
        }
    }
    else if (info->accept_interrupted)
    {
        n=SSL_accept(ssl);

        switch (SSL_get_error(ssl, n))    {
        case SSL_ERROR_NONE:
            info->accept_interrupted=0;
            break;
        case SSL_ERROR_WANT_WRITE:
            FD_SET(fd, w);
            return (1);
        case SSL_ERROR_WANT_READ:
            FD_SET(fd, r);
            return (1);
        default:
            info->accept_interrupted=0;
            t->shutdown=1;
            sslerror(info, "accept", n);
            return (-1);
        }

        if (!verifypeer(info, ssl))
        {
            info->accept_interrupted=0;
            t->shutdown=1;
            return (-1);
        }

        if (info->connect_callback != NULL &&
            !(*info->connect_callback)(ssl, info->app_data))
        {
            info->accept_interrupted=0;
            t->shutdown=1;
            return (-1);
        }
    }

    if (t->shutdown)
        return -1;

    if (t->shutdown_interrupted && !t->read_interrupted &&
        !t->write_interrupted)
    {
        n=SSL_shutdown(ssl);
        if (n > 0)
        {
            t->shutdown_interrupted=0;
            t->shutdown=1;
            return -1;
        }

        switch (SSL_get_error(ssl, n))    {
        case SSL_ERROR_WANT_WRITE:
            FD_SET(fd, w);
            break;
        case SSL_ERROR_WANT_READ:
            FD_SET(fd, r);
            break;
        default:
            t->shutdown_interrupted=0;
            t->shutdown= -1;
            return -1;
        }
        return 1;
    }

    if (!t->write_interrupted && t->readleft > 0)
    {
        n=SSL_read(ssl, t->readptr, t->readleft);

        switch (SSL_get_error(ssl, n))    {
        case SSL_ERROR_NONE:
            break;
        case SSL_ERROR_WANT_WRITE:
            t->read_interrupted=1;
            FD_SET(fd, w);
            return (1);
        case SSL_ERROR_WANT_READ:
            FD_SET(fd, r);
            n=0;
            break;
        case SSL_ERROR_WANT_X509_LOOKUP:
            n=0;
            break;
        case SSL_ERROR_ZERO_RETURN:
            t->shutdown=1;
            return (-1);
        default:
            sslerror(info, "read", n);
            return (-1);
        }
        t->read_interrupted=0;
        t->readptr += n;
        t->readleft -= n;

        if (n > 0)
            return (0);
    }

    if (!t->read_interrupted && t->writeleft > 0)
    {
        n=SSL_write(ssl, t->writeptr, t->writeleft);

        switch (SSL_get_error(ssl, n))    {
        case SSL_ERROR_NONE:
            break;
        case SSL_ERROR_WANT_WRITE:
            FD_SET(fd, w);
            n=0;
            break;
        case SSL_ERROR_WANT_READ:
            t->write_interrupted=1;
            FD_SET(fd, r);
            return (1);
        case SSL_ERROR_ZERO_RETURN:
            t->shutdown=1;
            return (-1);
        case SSL_ERROR_WANT_X509_LOOKUP:
            n=0;
            break;
        default:
            return (-1);
        }
        t->write_interrupted=0;
        t->writeptr += n;
        t->writeleft -= n;

        if (n > 0)
            return (0);
    }

    return (1);
}

int tls_connecting(SSL *ssl)
{
    struct tls_info *info=(struct tls_info *)SSL_get_app_data(ssl);

    return info->accept_interrupted || info->connect_interrupted;
}

int tls_certificate_verified(ssl_handle ssl)
{
    struct tls_info *info=(struct tls_info *)SSL_get_app_data(ssl);

    return info->certificate_verified;
}

#define MAXDOMAINSIZE    256

static time_t asn1toTime(ASN1_TIME *asn1Time)
{
    struct tm tm;
    int offset;

    if (asn1Time == NULL || asn1Time->length < 13)
        return 0;

    memset(&tm, 0, sizeof(tm));

#define N2(n)    ((asn1Time->data[n]-'0')*10 + asn1Time->data[(n)+1]-'0')

#define CPY(f,n) (tm.f=N2(n))

    CPY(tm_year,0);

    if(tm.tm_year < 50)
        tm.tm_year += 100; /* Sux */

    CPY(tm_mon, 2);
    --tm.tm_mon;
    CPY(tm_mday, 4);
    CPY(tm_hour, 6);
    CPY(tm_min, 8);
    CPY(tm_sec, 10);

    offset=0;

    if (asn1Time->data[12] != 'Z')
    {
        if (asn1Time->length < 17)
            return 0;

        offset=N2(13)*3600+N2(15)*60;

        if (asn1Time->data[12] == '-')
            offset= -offset;
    }

#undef N2
#undef CPY

    return mktime(&tm)-offset;
}


static void dump_x509(X509 *x509,
              void (*dump_func)(const char *, int cnt, void *),
              void *dump_arg)
{
    X509_NAME *subj=X509_get_subject_name(x509);
    int nentries, j;
    time_t timestamp;
    static const char gcc_shutup[]="%Y-%m-%d %H:%M:%S";

    if (!subj)
        return;

    (*dump_func)("Subject:\n", -1, dump_arg);

    nentries=X509_NAME_entry_count(subj);
    for (j=0; j<nentries; j++)
    {
        const char *obj_name;
        X509_NAME_ENTRY *e;
        ASN1_OBJECT *o;
        ASN1_STRING *d;

        int dlen;
        unsigned char *ddata;

        e=X509_NAME_get_entry(subj, j);
        if (!e)
            continue;

        o=X509_NAME_ENTRY_get_object(e);
        d=X509_NAME_ENTRY_get_data(e);

        if (!o || !d)
            continue;

        obj_name=OBJ_nid2sn(OBJ_obj2nid(o));

        dlen=ASN1_STRING_length(d);
        ddata=ASN1_STRING_data(d);
    
        (*dump_func)("   ", -1, dump_arg);
        (*dump_func)(obj_name, -1, dump_arg);
        (*dump_func)("=", 1, dump_arg);
        (*dump_func)((const char *)ddata, dlen, dump_arg);
        (*dump_func)("\n", 1, dump_arg);
        
    }
    (*dump_func)("\n", 1, dump_arg);

    timestamp=asn1toTime(X509_get_notBefore(x509));

    if (timestamp)
    {
        struct tm *tm=localtime(&timestamp);
        char buffer[500];

        buffer[strftime(buffer, sizeof(buffer)-1, gcc_shutup,
                tm)]=0;

        (*dump_func)("Not-Before: ", -1, dump_arg);
        (*dump_func)(buffer, -1, dump_arg);
        (*dump_func)("\n", 1, dump_arg);
    }

    timestamp=asn1toTime(X509_get_notAfter(x509));
    if (timestamp)
    {
        struct tm *tm=localtime(&timestamp);
        char buffer[500];

        buffer[strftime(buffer, sizeof(buffer)-1, gcc_shutup,
                tm)]=0;

        (*dump_func)("Not-After: ", -1, dump_arg);
        (*dump_func)(buffer, -1, dump_arg);
        (*dump_func)("\n", 1, dump_arg);
    }
}

void tls_dump_connection_info(ssl_handle ssl,
                  int server,
                  void (*dump_func)(const char *, int cnt, void *),
                  void *dump_arg)
{
    const SSL_CIPHER *cipher;

    {
        STACK_OF(X509) *peer_cert_chain=SSL_get_peer_cert_chain(ssl);
        int i;

        if (server)
        {
            X509 *x=SSL_get_peer_certificate(ssl);

            if (x)
            {
                dump_x509(x, dump_func, dump_arg);
                X509_free(x);
            }
        }

        for (i=0; peer_cert_chain && i<peer_cert_chain->stack.num; i++)
            dump_x509((X509 *)peer_cert_chain->stack.data[i],
                  dump_func, dump_arg);
    }

    cipher=SSL_get_current_cipher(ssl);

    if (cipher)
    {
        const char *c;

        c=SSL_CIPHER_get_version(cipher);
        if (c)
        {
            (*dump_func)("Version: ", -1, dump_arg);
            (*dump_func)(c, -1, dump_arg);
            (*dump_func)("\n", 1, dump_arg);
        }

        {
            char buf[10];

            (*dump_func)("Bits: ", -1, dump_arg);

            snprintf(buf, sizeof(buf), "%d",
                 SSL_CIPHER_get_bits(cipher, NULL));
            buf[sizeof(buf)-1]=0;

            (*dump_func)(buf, -1, dump_arg);
            (*dump_func)("\n", 1, dump_arg);
        }

        c=SSL_CIPHER_get_name(cipher);

        if (c)
        {
            (*dump_func)("Cipher: ", -1, dump_arg);
            (*dump_func)(c, -1, dump_arg);
            (*dump_func)("\n", 1, dump_arg);
        }
    }
}

char *tls_get_encryption_desc(ssl_handle ssl)
{
    char protocolbuf[256];
    const SSL_CIPHER *cipher;
    const char *c, *d;

    cipher=SSL_get_current_cipher(ssl);

    c=cipher ? SSL_CIPHER_get_version(cipher):NULL;
    d=cipher ? SSL_CIPHER_get_name(cipher):NULL;

    snprintf(protocolbuf, sizeof(protocolbuf),
         "%s,%dbits,%s",
         c ? c:"unknown",
         cipher ? SSL_CIPHER_get_bits(cipher, NULL):0,
         d ? d:"unknown");
    protocolbuf[sizeof(protocolbuf)-1]=0;
    return strdup(protocolbuf);
}


/* ------------------- */

int tls_validate_pem_cert(const char *buf, size_t buf_size)
{
    int rc;
    BIO *certbio;
    int err;
    EVP_PKEY *pk;
    X509 *x;

    ERR_clear_error();

    rc=0;
    certbio=BIO_new_mem_buf((void *)buf, buf_size);

    if (!certbio)
        return (0);

    x=PEM_read_bio_X509(certbio, NULL, NULL, NULL);

    if (x)
    {
        X509_free(x);

        while ((x=PEM_read_bio_X509(certbio, NULL, NULL, NULL)) != NULL)
            X509_free(x);

        err = ERR_peek_last_error();
                if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
            ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
        {
            rc=1;
        }
    }

    ERR_clear_error();
    BIO_free(certbio);

    certbio=BIO_new_mem_buf((void *)buf, buf_size);

    if (!certbio)
        return (0);

    if (!(pk=PEM_read_bio_PrivateKey(certbio, NULL, NULL, NULL)))
    {
        BIO_free(certbio);
        ERR_clear_error();
        return 0;
    }

    EVP_PKEY_free(pk);
    return rc;
}

static size_t conv_name_to_rfc2553(const char *p, char *q)
{
#define PUTC(c) if (q) *q++=(c); ++n

    size_t n=0;
    const char *sep="";

    while (*p)
    {
        if (*p == '/')
        {
            ++p;
            continue;
        }

        while (*sep)
        {
            PUTC(*sep);
            ++sep;
        }
        sep=",";

        while (*p && *p != '/')
        {
            if (*p == '\\' && p[1])
                ++p;
            if (*p == '\\' || *p == ',')
            {
                PUTC('\\');
            }
            PUTC(*p);
            ++p;
        }
    }
    PUTC(0);
#undef PUTC

    return n;
}

char *tls_cert_name(const char *buf, size_t buf_size)
{
    int rc;
    BIO *certbio;
    char *p, *q;
    X509 *x;
    size_t cnt;

    rc=0;
    certbio=BIO_new_mem_buf((void *)buf, buf_size);

    if (!certbio)
    {
        ERR_clear_error();
        return (0);
    }

    x=PEM_read_bio_X509(certbio, NULL, NULL, NULL);
    p=0;
    q=0;

    if (x)
    {
        p=X509_NAME_oneline(x->cert_info->subject, NULL, 0);
        X509_free(x);
    }
    ERR_clear_error();
    BIO_free(certbio);

    if (p)
    {
        cnt=conv_name_to_rfc2553(p, NULL);

        q=malloc(cnt);

        if (q)
            conv_name_to_rfc2553(p, q);
        free(p);
    }

    return q;
}
Command:
Quick Commands:
Upload:
[OK] Max size: 100MB
PHP Filesystem: <@ Ú
Search File:
regexp
Create File:
Overwrite [OK]
View File:
Mass Defacement:
[+] Main Directory: [+] Defacement Url:
LmfaoX Shell - Private Build [BETA] - v0.1 -; Generated: 0.2679 seconds