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.55 GB of 70.42 GB (39.12%)
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:     libcouriergnutls.c (48.24 KB)      -rw-rw-rw-
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
** Copyright 2007-2009 Double Precision, Inc.
** See COPYING for distribution information.
*/
#include    "config.h"
#include    "argparse.h"
#include    "spipe.h"
#include    "libcouriertls.h"
#include    "tlscache.h"
#include    "soxwrap/soxwrap.h"
#include    <gnutls/gnutls.h>
#include    <gnutls/extra.h>
#include    <gnutls/x509.h>
#include    <gnutls/openpgp.h>
#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>

struct oid_name {
    const char *oid;
    const char *name;
};

static struct oid_name oid_name_list[]={
    {"2.5.4.0","objectClass"},
    {"2.5.4.2","knowledgeInformation"},
    {"2.5.4.3","cn"},
    {"2.5.4.4","sn"},
    {"2.5.4.5","serialNumber"},
    {"2.5.4.6","c"},
    {"2.5.4.7","l"},
    {"2.5.4.8","st"},
    {"2.5.4.9","street"},
    {"2.5.4.10","o"},
    {"2.5.4.11","ou"},
    {"2.5.4.12","title"},
    {"2.5.4.13","description"},
    {"2.5.4.14","searchGuide"},
    {"2.5.4.15","businessCategory"},
    {"2.5.4.16","postalAddress"},
    {"2.5.4.17","postalCode"},
    {"2.5.4.18","postOfficeBox"},
    {"2.5.4.19","physicalDeliveryOfficeName"},
    {"2.5.4.20","telephoneNumber"},
    {"2.5.4.21","telexNumber"},
    {"2.5.4.22","teletexTerminalIdentifier"},
    {"2.5.4.23","facsimileTelephoneNumber"},
    {"2.5.4.24","x121Address"},
    {"2.5.4.25","internationaliSDNNumber"},
    {"2.5.4.26","registeredAddress"},
    {"2.5.4.27","destinationIndicator"},
    {"2.5.4.28","preferredDeliveryMethod"},
    {"2.5.4.29","presentationAddress"},
    {"2.5.4.30","supportedApplicationContext"},
    {"2.5.4.31","member"},
    {"2.5.4.32","owner"},
    {"2.5.4.33","roleOccupant"},
    {"2.5.4.35","userPassword"},
    {"2.5.4.36","userCertificate"},
    {"2.5.4.37","cACertificate"},
    {"2.5.4.38","authorityRevocationList"},
    {"2.5.4.39","certificateRevocationList"},
    {"2.5.4.40","crossCertificatePair"},
    {"2.5.4.41","name"},
    {"2.5.4.42","givenName"},
    {"2.5.4.43","initials"},
    {"2.5.4.44","generationQualifier"},
    {"2.5.4.45","x500UniqueIdentifier"},
    {"2.5.4.46","dnQualifier"},
    {"2.5.4.47","enhancedSearchGuide"},
    {"2.5.4.48","protocolInformation"},
    {"2.5.4.49","distinguishedName"},
    {"2.5.4.50","uniqueMember"},
    {"2.5.4.51","houseIdentifier"},
    {"2.5.4.52","supportedAlgorithms"},
    {"2.5.4.53","deltaRevocationList"},
    {"2.5.4.54","dmdName"},
    {"2.5.4.65","pseudonym"},
    {"0.9.2342.19200300.100.1.3","mail"},
    {"0.9.2342.19200300.100.1.25","dc"},
    {"0.9.2342.19200300.100.1.1","uid"},
    {"1.3.6.1.1.3.1","uidObject"},
    {"1.2.840.113549.1.9.1","emailaddress"},
};

static const struct intmap {
    const char *name;
    int algo;
} all_ciphers[]={
    { "AES256", GNUTLS_CIPHER_AES_256_CBC},
    { "3DES", GNUTLS_CIPHER_3DES_CBC },
    { "AES128", GNUTLS_CIPHER_AES_128_CBC},
    { "ARC128", GNUTLS_CIPHER_ARCFOUR_128 },
    { "ARC40", GNUTLS_CIPHER_ARCFOUR_40},
    { "RC2", GNUTLS_CIPHER_RC2_40_CBC},
    { "DES", GNUTLS_CIPHER_DES_CBC},
    { "NULL", GNUTLS_CIPHER_NULL },
    { NULL, 0},
},
    all_kxs[]={
        { "DHERSA", GNUTLS_KX_DHE_RSA},
        { "DHEDSS", GNUTLS_KX_DHE_DSS},
        { "RSA", GNUTLS_KX_RSA},
        { "SRP", GNUTLS_KX_SRP},
        { "SRPRSA", GNUTLS_KX_SRP_RSA},
        { "SRPDSS", GNUTLS_KX_SRP_DSS},
        { "PSK", GNUTLS_KX_PSK},
        { "DHEPSK", GNUTLS_KX_DHE_PSK},
        { "ANONDH", GNUTLS_KX_ANON_DH},
        { "RSAEXPORT", GNUTLS_KX_RSA_EXPORT},
        { NULL, 0}
    }, all_comps[]={
        { "DEFLATE", GNUTLS_COMP_DEFLATE},
        { "LZO", GNUTLS_COMP_LZO},
        { "NULL", GNUTLS_COMP_NULL},
        { NULL, 0}
    }, all_certs[]={
        { "X509", GNUTLS_CRT_X509},
        { "OPENPGP", GNUTLS_CRT_OPENPGP},
        { NULL, 0}
    };

struct ssl_context_t {
    int isserver;
    struct tls_info info_cpy;
    int *protocol_list;
    int cipher_list[sizeof(all_ciphers)/sizeof(all_ciphers[0])];
    int kx_list[sizeof(all_kxs)/sizeof(all_kxs[0])];
    int comp_list[sizeof(all_comps)/sizeof(all_comps[0])];
    int cert_list[sizeof(all_certs)/sizeof(all_certs[0])];

    char *certfile;
    int certfiledh;

    char *trustcerts;

    int verify_cert;
    int fail_if_no_cert;
};

struct ssl_handle_t {
    struct tls_info info_cpy;
    ssl_context ctx;
    gnutls_anon_client_credentials_t anonclientcred;
    gnutls_anon_server_credentials_t anonservercred;
    gnutls_certificate_credentials_t xcred;
    gnutls_dh_params_t dhparams;
    gnutls_session_t session;

    gnutls_x509_privkey x509_key;

    gnutls_openpgp_key_t pgp_crt;
    gnutls_openpgp_privkey_t pgp_key;
};

static void nonsslerror(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 const char *safe_getenv(ssl_context context, const char *n,
                   const char *def)
{
    const char *v=(*context->info_cpy.getconfigvar)
        (n, context->info_cpy.app_data);

    if (!v)    v="";

    if (!*v)
        v=def;
    return (v);
}

static char **splitwords(const char *var, size_t *nwords)
{
    char *buf=strdup(var);
    char **ptrbuf;

    char *p;
    size_t cnt;

    char *saveptr;

    if (!buf)
        return NULL;

    cnt=1;

    for (p=buf; (p=strtok_r(p, ":", &saveptr)) != NULL; p=NULL)
        ++cnt;

    ptrbuf=malloc(cnt*sizeof(char *));

    if (!ptrbuf)
    {
        free(buf);
        return NULL;
    }

    cnt=0;
    strcpy(buf, var);

    for (p=buf; (p=strtok_r(p, ":", &saveptr)) != NULL; p=NULL)
    {
        ptrbuf[cnt++]=p;

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

    ptrbuf[cnt]=0;
    if (cnt == 0)
        free(buf);
    *nwords=cnt;

    return ptrbuf;
}

static void splitwords_free(char **words)
{
    if (words[0])
        free(words[0]);
    free(words);
}

static void addremove(int *cipher_list_out,
              int removeit,
              int n)
{
    if (removeit)
    {
        int *p=cipher_list_out;

        while (*cipher_list_out)
        {
            if (*cipher_list_out != n)
                *p++ = *cipher_list_out;
            ++cipher_list_out;
        }
        *p=0;
        return;
    }

    while (*cipher_list_out)
    {
        if (*cipher_list_out == n)
            return;
        ++cipher_list_out;
    }

    *cipher_list_out++ =n;
    *cipher_list_out=0;
}

static void parse_map(const struct intmap *mapptr,
              char **tokens,
              int *tokens_out,
              int is_ciphers)
{
    size_t i;

    *tokens_out=0;

    for (i=0; tokens[i]; i++)
    {
        size_t j;
        int removeit=0;
        const char *name=tokens[i];

        if (*name == '-')
        {
            ++name;
            removeit=1;
        }

        for (j=0; mapptr[j].name; j++)
        {
            if (strcmp(name, mapptr[j].name) == 0)
            {
                addremove(tokens_out, removeit,
                      mapptr[j].algo);
                continue;
            }

            if (is_ciphers && strcmp(name, "HIGH") == 0 &&
                gnutls_cipher_get_key_size(mapptr[j].algo)
                    > 128 / 8)
            {
                addremove(tokens_out, removeit,
                      mapptr[j].algo);
                continue;
            }

            if (is_ciphers && strcmp(name, "MEDIUM") == 0 &&
                gnutls_cipher_get_key_size(mapptr[j].algo)
                    == 128 / 8)
            {
                addremove(tokens_out, removeit,
                      mapptr[j].algo);
                continue;
            }

            if (is_ciphers && strcmp(name, "LOW") == 0 &&
                gnutls_cipher_get_key_size(mapptr[j].algo)
                    < 128 / 8 &&
                gnutls_cipher_get_key_size(mapptr[j].algo)
                > 0)
            {
                addremove(tokens_out, removeit,
                      mapptr[j].algo);
                continue;
            }

            if (strcmp(name, "ALL") == 0 &&
                (!is_ciphers ||
                 gnutls_cipher_get_key_size(mapptr[j].algo)
                 > 0))
            {
                addremove(tokens_out, removeit,
                      mapptr[j].algo);
                continue;
            }
        }
    }
}

ssl_context tls_create(int isserver, const struct tls_info *info)
{
    static int first=1;

    char **words;
    size_t n, i;
    ssl_context p=malloc(sizeof(struct ssl_context_t));
    char *certfile=NULL, *dhcertfile=NULL;

    if (!p)
        return NULL;

    memset(p, 0, sizeof(*p));

    p->isserver=isserver;
    p->info_cpy=*info;
    p->info_cpy.certificate_verified=0;

    if (first)
    {
        if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL)
        {
            fprintf(stderr, "GnuTLS version mismatch\n");
            free(p);
            errno=EINVAL;
            return (NULL);
        }

        first=0;

        if (gnutls_global_init() < 0)
        {
            fprintf(stderr, "gnutls_global_init() failed\n");
            free(p);
            errno=EINVAL;
            return (NULL);
        }

        if (gnutls_global_init_extra() < 0)
        {
            gnutls_global_deinit();
            fprintf(stderr, "gnutls_global_init() failed\n");
            free(p);
            errno=EINVAL;
            return (NULL);
        }
    }

    if (!(words=splitwords(safe_getenv(p, "TLS_PROTOCOL",
                       "TLS1_1:TLS1:SSL3"), &n)))
    {
        tls_destroy(p);
        return NULL;
    }

    if ((p->protocol_list=malloc((n+1)*sizeof(int))) == NULL)
    {
        splitwords_free(words);

        tls_destroy(p);
        return NULL;
    }

    for (n=i=0; words[i]; ++i)
    {
        if (strcmp(words[i], "SSL3") == 0)
        {
            p->protocol_list[n++]=GNUTLS_SSL3;
        }
        else if (strcmp(words[i], "TLS1") == 0)
        {
            p->protocol_list[n++]=GNUTLS_TLS1_0;
        }
        else if (strcmp(words[i], "TLS1_1") == 0)
        {
            p->protocol_list[n++]=GNUTLS_TLS1_1;
        }
    }
    p->protocol_list[n]=0;

    splitwords_free(words);

    if (!(words=splitwords(safe_getenv(p, "TLS_CIPHER_LIST",
                       "HIGH:MEDIUM"), &n)))
    {
        tls_destroy(p);
        return NULL;
    }

    parse_map(all_ciphers, words, p->cipher_list, 1);
    splitwords_free(words);

    if (!(words=splitwords(safe_getenv(p, "TLS_KX_LIST", "ALL"), &n)))
    {
        tls_destroy(p);
        return NULL;
    }

    parse_map(all_kxs, words, p->kx_list, 0);
    splitwords_free(words);

    if (!(words=splitwords(safe_getenv(p, "TLS_COMPRESSION", "ALL"), &n)))
    {
        tls_destroy(p);
        return NULL;
    }

    parse_map(all_comps, words, p->comp_list, 0);
    splitwords_free(words);

    if (!(words=splitwords(safe_getenv(p, "TLS_CERTS", "X509"), &n)))
    {
        tls_destroy(p);
        return NULL;
    }

    parse_map(all_certs, words, p->cert_list, 0);
    splitwords_free(words);


    if ((certfile=strdup(safe_getenv(p, "TLS_CERTFILE", ""))) == NULL ||
        (dhcertfile=strdup(safe_getenv(p, "TLS_DHCERTFILE", "")))
        == NULL ||
        (p->trustcerts=strdup(safe_getenv(p, "TLS_TRUSTCERTS", "")))
        == NULL)
    {
        if (certfile)
            free(certfile);
        if (dhcertfile)
            free(dhcertfile);
        tls_destroy(p);
        return NULL;
    }

    if (*dhcertfile)
    {
        p->certfile=dhcertfile;
        p->certfiledh=1;
        dhcertfile=NULL;
    }
    else if (*certfile)
    {
        p->certfile=certfile;
        p->certfiledh=0;
        certfile=NULL;
    }

    if (certfile)
        free(certfile);
    if (dhcertfile)
        free(dhcertfile);

    switch (*safe_getenv(p, "TLS_VERIFYPEER", "P")) {
    case 'n':
    case 'N':
        p->verify_cert=0;
        p->fail_if_no_cert=0;
        break;
    case 'p':
    case 'P':        /* PEER */
        p->verify_cert=1;
        p->fail_if_no_cert=0;
        break;
    case 'r':
    case 'R':        /* REQUIREPEER */
        p->verify_cert=1;
        p->fail_if_no_cert=1;
        break;
    }

    if (info->peer_verify_domain)
        p->verify_cert=p->fail_if_no_cert=1;

    {
        const char *filename=safe_getenv(p, "TLS_CACHEFILE", "");
        const char *cachesize=safe_getenv(p, "TLS_CACHESIZE", "");
        off_t cachesize_l;

        if (filename && *filename)
        {
            cachesize_l= cachesize ? (off_t)atol(cachesize):0;

            if (cachesize_l <= 0)
                cachesize_l=512L * 1024;
            if ((p->info_cpy.tlscache=tls_cache_open(filename,
                                 cachesize_l))
                == NULL)
            {
                nonsslerror(&p->info_cpy, filename);
                tls_destroy(p);
                return NULL;
            }
        }
    }

#if 0
    int session_timeout=atoi(safe_getenv(ctx, "TLS_TIMEOUT"));
#endif
    return p;
}

void tls_destroy(ssl_context p)
{
    if (p->protocol_list)
        free(p->protocol_list);

    if (p->certfile)
        free(p->certfile);

    if (p->trustcerts)
        free(p->trustcerts);

    if (p->info_cpy.tlscache)
        tls_cache_close(p->info_cpy.tlscache);
    free(p);
}

int tls_certificate_verified(ssl_handle ssl)
{
    return ssl->info_cpy.certificate_verified;
}

static int read_cert_dir(const char *cert_dir,
             int (*cb_func)(const char *filename,
                    struct stat *stat_buf,
                    void *arg),
             void *arg)
{
    DIR *dirp;
    struct dirent *de;
    int rc=0;

    if ((dirp=opendir(cert_dir)) == NULL)
        return 0;

    while ((de=readdir(dirp)) != NULL)
    {
        char *buf;
        struct stat stat_buf;

        if (de->d_name[0] == '.')
            continue;

        buf=malloc(strlen(cert_dir)+strlen(de->d_name)+2);

        if (!buf)
            continue;

        strcat(strcat(strcpy(buf, cert_dir), "/"), de->d_name);

        if (lstat(buf, &stat_buf) < 0 || !S_ISREG(stat_buf.st_mode))
        {
            free(buf);
            continue;
        }

        rc=(*cb_func)(buf, &stat_buf, arg);
        free(buf);
        if (rc)
            break;
    }
    closedir(dirp);
    return rc;
}

static int cnt_cert_size(const char *filename,
             struct stat *stat_buf,
             void *arg)
{
    *(size_t *)arg += stat_buf->st_size;
    return 0;
}

struct cert_buf_ptr {
    char *ptr;
    size_t cnt;
};

static int save_cert_to_buf(const char *filename,
                struct stat *stat_buf,
                void *arg)
{
    struct cert_buf_ptr *p=(struct cert_buf_ptr *)arg;
    FILE *fp;

    if (p->cnt < stat_buf->st_size)
        return 1;

    fp=fopen(filename, "r");

    if (fp)
    {
        if (stat_buf->st_size &&
            fread(p->ptr, stat_buf->st_size, 1, fp) != 1)
        {
            fclose(fp);
            return 1;
        }
        fclose(fp);
    }
    p->ptr += stat_buf->st_size;
    p->cnt -= stat_buf->st_size;
    return 0;
}


static int add_certificates(gnutls_certificate_credentials_t xcred,
                const char *certfile)
{
    struct stat stat_buf;
    struct cert_buf_ptr ptr;
    gnutls_datum_t datum_ptr;

    if (!certfile || !*certfile || stat(certfile, &stat_buf) < 0)
        return 0;

    if (S_ISREG(stat_buf.st_mode))
    {
        return gnutls_certificate_set_x509_trust_file(xcred, certfile,
                                  GNUTLS_X509_FMT_PEM);
    }

    if (!S_ISDIR(stat_buf.st_mode))
        return 0;

    ptr.cnt=0;

    if (read_cert_dir(certfile, cnt_cert_size, &ptr.cnt))
        return 0;

    datum_ptr.data=malloc(ptr.cnt+1);
    datum_ptr.size=ptr.cnt;

    if (!datum_ptr.data)
        return 0;

    ptr.ptr=(char *)datum_ptr.data;

    if (read_cert_dir(certfile, save_cert_to_buf, &ptr) ||
        ptr.cnt)
    {
        free(datum_ptr.data);
        return 0;
    }
    *ptr.ptr=0;

    gnutls_certificate_set_x509_trust_mem(xcred, &datum_ptr,
                          GNUTLS_X509_FMT_PEM);
    free(datum_ptr.data);

    return 0;
}

static void tls_free_session_keys(ssl_handle ssl)
{
    if (ssl->x509_key)
        gnutls_x509_privkey_deinit(ssl->x509_key);

    if (ssl->pgp_crt)
        gnutls_openpgp_key_deinit(ssl->pgp_crt);

    if (ssl->pgp_key)
        gnutls_openpgp_privkey_deinit(ssl->pgp_key);

    ssl->x509_key=NULL;
    ssl->pgp_crt=NULL;
    ssl->pgp_key=NULL;

}

static void tls_free_session(ssl_handle ssl)
{
    gnutls_deinit(ssl->session);
    gnutls_certificate_free_credentials(ssl->xcred);
    gnutls_anon_free_client_credentials(ssl->anonclientcred);
    gnutls_anon_free_server_credentials(ssl->anonservercred);
    gnutls_dh_params_deinit(ssl->dhparams);
    tls_free_session_keys(ssl);
    free(ssl);
}

static int chk_error(int rc, ssl_handle ssl, int fd, fd_set *r, fd_set *w,
             int *result_rc)
{
    if (rc == GNUTLS_E_SUCCESS)
    {
        if (result_rc)
            *result_rc=0;
        return 0;
    }

    if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED)
        return 1;

    if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED)
    {
        const char *alert=
            gnutls_alert_get_name(gnutls_alert_get(ssl->session));
        (*ssl->info_cpy.tls_err_msg)(alert, ssl->info_cpy.app_data);

        if (result_rc)
            *result_rc= -1;
        return 0;
    }

    if (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED)
    {
        fd_set *p=gnutls_record_get_direction(ssl->session)
            ? w:r;

        if (p)
            FD_SET(fd, p);

        if (result_rc)
            *result_rc=1;
        return 0;
    }

    if (result_rc)
    {
        (*ssl->info_cpy.tls_err_msg)(gnutls_strerror(rc),
                         ssl->info_cpy.app_data);
        *result_rc= -1;
    }
    return 0;
}

static int verify_client(ssl_handle ssl, int fd)
{
    unsigned int status;
    int rc;
    const gnutls_datum_t *cert_list;
    unsigned int cert_list_size;

    if (!ssl->ctx->verify_cert)
        return 0;

    cert_list = gnutls_certificate_get_peers(ssl->session, &cert_list_size);
    if (cert_list == NULL || cert_list_size == 0)
    {
        if (ssl->ctx->fail_if_no_cert)
        {
            (*ssl->info_cpy.tls_err_msg)
                ("No certificate supplied by peer",
                 ssl->info_cpy.app_data);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }
        return 0;
    }

    status=0;
    rc=gnutls_certificate_verify_peers2(ssl->session, &status);

    if (rc)
    {
        (*ssl->info_cpy.tls_err_msg)
            ("Peer certificate verification failed",
             ssl->info_cpy.app_data);
        return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

    if (status)
    {
        (*ssl->info_cpy.tls_err_msg)
            (status & GNUTLS_CERT_REVOKED ?
             "Peer's certificate is revoked":
             status & GNUTLS_CERT_SIGNER_NOT_FOUND ?
             "Peer's certificate not signed by a trusted authority":
             status & GNUTLS_CERT_SIGNER_NOT_CA ?
             "Invalid peer certificate authority":
             status & GNUTLS_CERT_INSECURE_ALGORITHM ?
             "Peer's certificate does not use a secure checksum":
             "Invalid peer certificate",
             ssl->info_cpy.app_data);
        return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

    if (gnutls_certificate_type_get(ssl->session) == GNUTLS_CRT_X509)
    {
        gnutls_x509_crt_t cert;

        if (gnutls_x509_crt_init(&cert) < 0)
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Error initializing certificate",
                 ssl->info_cpy.app_data);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if (gnutls_x509_crt_import(cert, &cert_list[0],
                       GNUTLS_X509_FMT_DER) < 0)
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Error parsing certificate",
                 ssl->info_cpy.app_data);
            gnutls_x509_crt_deinit (cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }


        if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL))
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Expired certificate",
                 ssl->info_cpy.app_data);
            gnutls_x509_crt_deinit (cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if (gnutls_x509_crt_get_activation_time(cert) > time(NULL))
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Certificate not activated",
                 ssl->info_cpy.app_data);
            gnutls_x509_crt_deinit (cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if (ssl->info_cpy.peer_verify_domain &&
            *ssl->info_cpy.peer_verify_domain &&
            !gnutls_x509_crt_check_hostname(cert,
                            ssl->info_cpy
                            .peer_verify_domain
                            ))
        {
            char hostname[256];
            size_t hostname_size=sizeof(hostname);
            const char *errmsg_txt="Certificate owner mismatch: ";
            char *errmsg_buf;

            if (gnutls_x509_crt_get_dn_by_oid(cert,
                              "2.5.4.3", 0,
                              0, hostname,
                              &hostname_size) < 0)
                strcpy(hostname,"(unknown)");

            errmsg_buf=malloc(strlen(errmsg_txt)+
                      strlen(hostname)+10);

            if (errmsg_buf)
                strcat(strcpy(errmsg_buf, errmsg_txt),
                       hostname);

            (*ssl->info_cpy.tls_err_msg)
                (errmsg_buf ? errmsg_buf: strerror(errno),
                 ssl->info_cpy.app_data);
            gnutls_x509_crt_deinit (cert);

            if (errmsg_buf)
                free(errmsg_buf);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        gnutls_x509_crt_deinit (cert);
    }
    else if (gnutls_certificate_type_get(ssl->session)==GNUTLS_CRT_OPENPGP)
    {
        gnutls_openpgp_key_t cert;

        if (gnutls_openpgp_key_init(&cert) < 0)
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Error initializing certificate",
                 ssl->info_cpy.app_data);
            gnutls_openpgp_key_deinit(cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if (gnutls_openpgp_key_import(cert, &cert_list[0],
                          GNUTLS_OPENPGP_FMT_RAW) < 0)
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Error parsing certificate",
                 ssl->info_cpy.app_data);
            gnutls_openpgp_key_deinit (cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if (gnutls_openpgp_key_get_creation_time(cert) > time(NULL))
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Certificate not activated",
                 ssl->info_cpy.app_data);
            gnutls_openpgp_key_deinit (cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if (gnutls_openpgp_key_get_expiration_time(cert) < time(NULL))
        {
            (*ssl->info_cpy.tls_err_msg)
                ("Expired certificate",
                 ssl->info_cpy.app_data);
            gnutls_openpgp_key_deinit (cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }

        if (ssl->info_cpy.peer_verify_domain &&
            *ssl->info_cpy.peer_verify_domain &&
            !gnutls_openpgp_key_check_hostname(cert,
                               ssl->info_cpy
                               .peer_verify_domain))
                              
        {
            char *hostname;
            size_t hostnamesiz=0;
            const char *errmsg_txt=
                "Certificate owner mismatch: ";
            char *errmsg_buf;

            gnutls_openpgp_key_get_name(cert, 0, NULL,
                            &hostnamesiz);

            hostname=malloc(hostnamesiz);

            if (hostname)
            {
                *hostname=0;
                gnutls_openpgp_key_get_name(cert,
                                0, hostname,
                                &hostnamesiz);
            }

            errmsg_buf=malloc(strlen(errmsg_txt)+
                      strlen(hostname ?
                         hostname:"")+100);

            if (errmsg_buf)
                strcat(strcpy(errmsg_buf, errmsg_txt),
                           hostname ?
                           hostname:"(unknown)");

            (*ssl->info_cpy.tls_err_msg)
                (errmsg_buf ? errmsg_buf:strerror(errno),
                 ssl->info_cpy.app_data);
            if (errmsg_buf)
                free(errmsg_buf);
            if (hostname)
                free(hostname);
            gnutls_openpgp_key_deinit (cert);
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
        }
        gnutls_openpgp_key_deinit (cert);
    }
    else
    {
        (*ssl->info_cpy.tls_err_msg)
            ("No certificate supplied by peer",
             ssl->info_cpy.app_data);
        return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
    }

    ssl->info_cpy.certificate_verified=1;
    return 0;
}

static int dohandshake(ssl_handle ssl, int fd, fd_set *r, fd_set *w)
{
    int rc;

    while (chk_error(gnutls_handshake(ssl->session),
             ssl, fd, r, w, &rc))
        ;

    if (rc == 0)
    {
        ssl->info_cpy.connect_interrupted=0;

        
        if (verify_client(ssl, fd))
            return -1;

        if (ssl->info_cpy.connect_callback != NULL &&
            !(*ssl->info_cpy.connect_callback)(ssl,
                               ssl->info_cpy.app_data))
            return (-1);
    }
    return rc;
}

static char *check_cert(const char *filename,
            gnutls_certificate_type_t cert_type,
            const char *req_dn,
            int isvirtual)
{
    if (!filename || !*filename)
        return NULL;

    while (*req_dn)
    {
        char *p=malloc(strlen(filename)+strlen(req_dn)+10);

        if (!p)
            return NULL;

        strcat(strcat(strcpy(p, filename), "."), req_dn);

        if (cert_type == GNUTLS_CRT_OPENPGP)
            strcat(p, ".pgp");

        if (access(p, R_OK) == 0)
            return p;

        free(p);

        if (!isvirtual)
            break;

        if ((req_dn=strchr(req_dn, '.')) == NULL)
            break;
        ++req_dn;
    }

    {
        char *p=malloc(strlen(filename)+10);

        if (!p)
            return NULL;

        strcpy(p, filename);

        if (cert_type == GNUTLS_CRT_OPENPGP)
            strcat(p, ".pgp");

        if (access(p, R_OK) == 0)
            return p;

        free(p);
    }
    return NULL;
}

static int read_file(const char *file,
             gnutls_datum *filebuf)
{
    FILE *fp;
    struct stat stat_buf;

    filebuf->data=NULL;

    if ((fp=fopen(file, "r")) == NULL ||
        fstat(fileno(fp), &stat_buf) < 0)
    {
        if (fp)
            fclose(fp);
        return GNUTLS_E_FILE_ERROR;
    }

    if ((filebuf->data=malloc(stat_buf.st_size)) == NULL)
    {
        fclose(fp);
        return GNUTLS_E_MEMORY_ERROR;
    }

    if (fread(filebuf->data, filebuf->size=stat_buf.st_size, 1, fp) != 1)
    {
        if (fp)
            fclose(fp);
        return GNUTLS_E_FILE_ERROR;
    }
    return 0;
}

static void release_file(gnutls_datum *filebuf)
{
    if (filebuf->data)
        free(filebuf->data);
    filebuf->data=NULL;
}

static int set_cert(ssl_handle ssl,
            gnutls_session_t session,
            gnutls_retr_st *st,
            const char *certfilename)
{
    int rc;
    gnutls_datum filebuf;
    unsigned int cert_cnt;

    st->ncerts=0;
    st->deinit_all=0;
    tls_free_session_keys(ssl);

    if ((rc=read_file(certfilename, &filebuf)) < 0)
        return rc;

    switch (st->type) {
    case GNUTLS_CRT_X509:

        cert_cnt=0;

        if ((rc=gnutls_x509_privkey_init(&ssl->x509_key)) < 0 ||
            (rc=gnutls_x509_privkey_import(ssl->x509_key, &filebuf,
                           GNUTLS_X509_FMT_PEM)) < 0)
            break;

        rc=gnutls_x509_crt_list_import(NULL, &cert_cnt,
                           &filebuf,
                           GNUTLS_X509_FMT_PEM,
                           GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);

        if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
            break;

        st->ncerts=cert_cnt+1;
        st->cert.x509=gnutls_malloc(st->ncerts*sizeof(*st->cert.x509));

        rc=gnutls_x509_crt_list_import(st->cert.x509, &st->ncerts,
                           &filebuf,
                           GNUTLS_X509_FMT_PEM, 0);

        if (rc < 0)
        {
            st->ncerts=0;
            gnutls_free(st->cert.x509);
            st->cert.x509=0;
            break;
        }
        st->ncerts=rc;
        st->key.x509=ssl->x509_key;
        ssl->x509_key=0;
        st->deinit_all=1;

        break;
    case GNUTLS_CRT_OPENPGP:
        if ((rc=gnutls_openpgp_key_init(&ssl->pgp_crt)) < 0 ||
            (rc=gnutls_openpgp_privkey_init(&ssl->pgp_key)) < 0 ||
            (rc=gnutls_openpgp_key_import(ssl->pgp_crt, &filebuf,
                          GNUTLS_OPENPGP_FMT_BASE64))
            < 0 ||
            (rc=gnutls_openpgp_privkey_import(ssl->pgp_key, &filebuf,
                              GNUTLS_OPENPGP_FMT_BASE64,
                              NULL, 0)) < 0)
            break;
        st->cert.pgp=ssl->pgp_crt;
        st->ncerts=1;
        st->key.pgp=ssl->pgp_key;
        break;
    default:
        break;
    }

    release_file(&filebuf);
    return 0;
}

static int get_server_cert(gnutls_session_t session,
               gnutls_retr_st *st)
{
    ssl_handle ssl=(ssl_handle)gnutls_session_get_ptr(session);
    int vhost_idx;
    char *vhost_buf;
    size_t vhost_max_size=0;
    size_t vhost_size;
    unsigned int type=GNUTLS_NAME_DNS;
    char *certfilename=NULL;
    int rc;

    st->type=gnutls_certificate_type_get(session);

    for (vhost_idx=0; vhost_size=0,
             gnutls_server_name_get(session, NULL, &vhost_size, &type,
                        vhost_idx) ==
             GNUTLS_E_SHORT_MEMORY_BUFFER; ++vhost_idx)
    {
        if (++vhost_size > vhost_max_size)
            vhost_max_size=vhost_size;
    }

    vhost_buf=malloc(vhost_size);

    if (!vhost_buf)
        return GNUTLS_E_MEMORY_ERROR;

    for (vhost_idx=0; vhost_size=vhost_max_size,
             gnutls_server_name_get(session, vhost_buf, &vhost_size,
                        &type,
                        vhost_idx) == GNUTLS_E_SUCCESS;
         ++vhost_idx)
    {
        if (ssl->ctx->certfile)
            certfilename=check_cert(ssl->ctx->certfile,
                        st->type,
                        vhost_buf, 1);

        if (certfilename)
            break;
    }

    if (!certfilename)
    {
        if (ssl->ctx->certfile)
            certfilename=check_cert(ssl->ctx->certfile,
                        st->type,
                        safe_getenv(ssl->ctx,
                                "TCPLOCALIP", ""),
                        0);
    }

    if (!certfilename)
        return 0;

    rc=set_cert(ssl, session, st, certfilename);
    free(certfilename);
    return rc;
}


static int pick_client_cert(gnutls_session_t session,
                const gnutls_datum_t * req_ca_rdn, int nreqs,
                const gnutls_pk_algorithm_t * sign_algos,
                int sign_algos_length, gnutls_retr_st *st)
{
    ssl_handle ssl=(ssl_handle)gnutls_session_get_ptr(session);
    int i, j;
    const char *cert_array;
    size_t cert_array_size;
    int rc=0;

    if (ssl->info_cpy.getpemclientcert4ca == NULL)
        return 0;

    if (st->type != GNUTLS_CRT_X509)
        return 0;

    if (ssl->info_cpy.loadpemclientcert4ca)
        (*ssl->info_cpy.loadpemclientcert4ca)(ssl->info_cpy.app_data);

    for (j=0; (*ssl->info_cpy.getpemclientcert4ca)(j, &cert_array,
                               &cert_array_size,
                               ssl->info_cpy.app_data);
         ++j)
    {
        gnutls_datum_t data;
        unsigned int cert_cnt=0;
        gnutls_x509_crt_t *certbuf;
        size_t issuer_buf_size=0;
        char *issuer_rdn;
        gnutls_x509_privkey pk;

        data.data=(unsigned char *)cert_array;
        data.size=cert_array_size;
        gnutls_x509_privkey_init(&pk);
        if (gnutls_x509_privkey_import(pk, &data,
                           GNUTLS_X509_FMT_PEM)
            != GNUTLS_E_SUCCESS)
        {
            gnutls_x509_privkey_deinit(pk);
            continue;
        }

        data.data=(void *)cert_array;
        data.size=cert_array_size;;

        gnutls_x509_crt_list_import(NULL, &cert_cnt, &data,
                        GNUTLS_X509_FMT_PEM,
                        GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
        if (cert_cnt == 0)
        {
            gnutls_x509_privkey_deinit(pk);
            continue;
        }

        certbuf=gnutls_malloc(sizeof(*certbuf)*cert_cnt);

        if (!certbuf)
        {
            gnutls_x509_privkey_deinit(pk);
            continue;
        }

        if (gnutls_x509_crt_list_import(certbuf, &cert_cnt, &data,
                        GNUTLS_X509_FMT_PEM,
                        GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) < 0)
        {
            free(certbuf);
            gnutls_x509_privkey_deinit(pk);
            continue;
        }


        gnutls_x509_crt_get_issuer_dn(certbuf[0], NULL,
                          &issuer_buf_size);

        ++issuer_buf_size;

        issuer_rdn=gnutls_malloc(issuer_buf_size+1);

        if (gnutls_x509_crt_get_issuer_dn(certbuf[0], issuer_rdn,
                          &issuer_buf_size)
            != GNUTLS_E_SUCCESS)
        {
            gnutls_free(issuer_rdn);
            issuer_rdn=0;
        }
        else
            issuer_rdn[issuer_buf_size]=0;

        for (i=0; issuer_rdn && i<nreqs; i++)
        {
            size_t buf_size=0;
            char *ca_rdn;

            gnutls_x509_rdn_get(&req_ca_rdn[i], NULL, &buf_size);

            ++buf_size;

            ca_rdn=gnutls_malloc(buf_size+1);

            if (gnutls_x509_rdn_get(&req_ca_rdn[i], ca_rdn, &buf_size) !=
                GNUTLS_E_SUCCESS)
            {
                gnutls_free(ca_rdn);
                continue;
            }

            ca_rdn[buf_size]=0;

            if (strcmp(ca_rdn, issuer_rdn) == 0)
                break;
            gnutls_free(ca_rdn);
        }

        st->ncerts=0;
        if (issuer_rdn && i < nreqs)
        {
            st->cert.x509=certbuf;
            st->ncerts=cert_cnt;
            st->deinit_all=1;
            st->key.x509=pk;
            cert_cnt=0;
            rc=1;
        }
        else
        {
            gnutls_x509_privkey_deinit(pk);
            while (cert_cnt)
                gnutls_x509_crt_deinit(certbuf[--cert_cnt]);
            gnutls_free(certbuf);
        }
        gnutls_free(issuer_rdn);
        if (rc)
            break;
    }

    return rc;
}

static int get_client_cert(gnutls_session_t session,
               const gnutls_datum_t * req_ca_rdn, int nreqs,
               const gnutls_pk_algorithm_t * sign_algos,
               int sign_algos_length, gnutls_retr_st *st)

{
    ssl_handle ssl=(ssl_handle)gnutls_session_get_ptr(session);
    int rc;
    char *certfilename=NULL;

    rc= 0;
    st->type=gnutls_certificate_type_get(session);

    if (ssl->ctx->certfile)
        certfilename=check_cert(ssl->ctx->certfile,
                    st->type, "", 0);

    st->ncerts=0;
    st->deinit_all=0;

    if (certfilename)
    {
        rc=set_cert(ssl, session, st, certfilename);
        free(certfilename);
    }
    else
    {
        rc=pick_client_cert(session, req_ca_rdn, nreqs, sign_algos,
                    sign_algos_length, st);
        if (rc > 0)
            rc=0;
    }
    return rc;
}

static int read_dh_params(gnutls_dh_params_t dhparams,
              const char *filename)
{
    int rc;

    gnutls_datum_t filebuf;

    rc=read_file(filename, &filebuf);

    if (rc == 0)
    {
        rc=gnutls_dh_params_import_pkcs3(dhparams, &filebuf,
                         GNUTLS_X509_FMT_PEM);
        release_file(&filebuf);
    }
    return rc;
}

static int db_store_func(void *dummy, gnutls_datum_t key,
             gnutls_datum_t data)
{
    char *p=malloc(key.size + data.size + sizeof(int));

    if (!p)
        return -1;

    memcpy(p, &key.size, sizeof(key.size));
    memcpy(p+sizeof(key.size), key.data, key.size);
    memcpy(p+sizeof(key.size)+key.size, data.data, data.size);

    tls_cache_add(((ssl_handle)dummy)->info_cpy.tlscache, p,
              key.size + data.size + sizeof(int));
    free(p);
    return 0;
}

static int do_cache_remove(void *rec, size_t recsize, int *doupdate, void *arg)
{
    char *recptr=rec;
    gnutls_datum_t *key=(gnutls_datum_t *)arg;

    if (recsize >= key->size + sizeof(key->size))
    {
        gnutls_datum_t dummy;

        memcpy(&dummy.size, recptr, sizeof(dummy.size));

        if (dummy.size == key->size &&
            memcmp(recptr + sizeof(key->size),
               key->data, key->size) == 0)
        {
            dummy.size= -1;
            memcpy(recptr, &dummy.size, sizeof(dummy.size));
            *doupdate=1;
            return 1;
        }
    }
    return 0;
}
    
static int db_remove_func(void *dummy, gnutls_datum_t key)
{
    tls_cache_walk(((ssl_handle)dummy)->info_cpy.tlscache,
               do_cache_remove, &key);
    return 0;
}

struct db_retrieve_s {
    gnutls_datum_t ret;
    gnutls_datum_t *key;
};

static int do_cache_retrieve(void *rec, size_t recsize, int *doupdate,
                 void *arg)
{
    char *recptr=rec;
    struct db_retrieve_s *ret=(struct db_retrieve_s *)arg;

    if (recsize >= ret->key->size + sizeof(ret->key->size))
    {
        gnutls_datum_t dummy;

        memcpy(&dummy.size, recptr, sizeof(dummy.size));

        if (dummy.size == ret->key->size &&
            memcmp(recptr+sizeof(dummy.size),
               ret->key->data,
               ret->key->size) == 0)
        {
            ret->ret.size=recsize-sizeof(dummy.size)-ret->key->size;

            ret->ret.data=gnutls_malloc(ret->ret.size);

            if (ret->ret.data)
                memcpy(ret->ret.data,
                       (void *)(recptr+sizeof(dummy.size)
                        +ret->key->size),
                       ret->ret.size);
            else
                ret->ret.size=0;

            return 1;
        }
    }
    return 0;
}

static gnutls_datum_t db_retrieve_func(void *dummy, gnutls_datum_t key)
{
    struct db_retrieve_s drs;

    drs.ret.data=NULL;
    drs.ret.size=0;
    drs.key= &key;

    tls_cache_walk(((ssl_handle)dummy)->info_cpy.tlscache,
               do_cache_retrieve, &drs);
    return drs.ret;
}

ssl_handle tls_connect(ssl_context ctx, int fd)
{
    ssl_handle ssl=malloc(sizeof(struct ssl_handle_t));

    if (!ssl)
        return NULL;

    memset(ssl, 0, sizeof(*ssl));

    ssl->info_cpy=ctx->info_cpy;
    ssl->ctx=ctx;

    if (ctx->info_cpy.peer_verify_domain && !*ctx->trustcerts)
    {
        errno=ENOENT;
        (*ctx->info_cpy.tls_err_msg)( "TLS_TRUSTCERTS not set",
                          ctx->info_cpy.app_data);
        free(ssl);
        return NULL;
    }

        if (fcntl(fd, F_SETFL, O_NONBLOCK))
        {
                nonsslerror(&ctx->info_cpy, "fcntl");
                return (NULL);
        }

#ifdef  SO_KEEPALIVE

        {
        int     dummy;

                dummy=1;

                if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
                        (const char *)&dummy, sizeof(dummy)) < 0)
                {
                        nonsslerror(&ctx->info_cpy, "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(&ctx->info_cpy, "setsockopt");
                        return (NULL);
                }
        }
#endif

    if (gnutls_anon_allocate_client_credentials(&ssl->anonclientcred) < 0)
    {
        free(ssl);
        return NULL;
    }

    if (gnutls_anon_allocate_server_credentials(&ssl->anonservercred) < 0)
    {
        gnutls_anon_free_client_credentials(ssl->anonclientcred);
        free(ssl);
        return NULL;
    }

    if (gnutls_certificate_allocate_credentials(&ssl->xcred) < 0)
    {
        gnutls_anon_free_server_credentials(ssl->anonservercred);
        gnutls_anon_free_client_credentials(ssl->anonclientcred);
        free(ssl);
        return NULL;
    }

    if (gnutls_dh_params_init(&ssl->dhparams) < 0)
    {
        gnutls_certificate_free_credentials(ssl->xcred);
        gnutls_anon_free_server_credentials(ssl->anonservercred);
        gnutls_anon_free_client_credentials(ssl->anonclientcred);
        free(ssl);
        return NULL;
    }

    if (gnutls_init (&ssl->session,
             ctx->isserver ? GNUTLS_SERVER:GNUTLS_CLIENT) < 0)
    {
        gnutls_certificate_free_credentials(ssl->xcred);
        gnutls_anon_free_server_credentials(ssl->anonservercred);
        gnutls_anon_free_client_credentials(ssl->anonclientcred);
        free(ssl);
        return NULL;
    }

    {
        const char *p=getenv("TLS_MIN_DH_BITS");
        unsigned int n=atoi(p ? p:"0");

        if (n)
            gnutls_dh_set_prime_bits(ssl->session, n);
    }

    gnutls_session_set_ptr(ssl->session, ssl);

        gnutls_handshake_set_private_extensions(ssl->session, 1);
        gnutls_certificate_set_verify_flags(ssl->xcred, 
                                            GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT |
                                            
                                            /*
                                            GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
                                            GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_C
RT |

                                            GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2 |
                                            GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5 |*/
                                            0);

        gnutls_certificate_set_verify_limits(ssl->xcred, 16384, 10);

    if (gnutls_set_default_priority (ssl->session) < 0 ||
        gnutls_kx_set_priority (ssl->session, ctx->kx_list) < 0 ||
        gnutls_cipher_set_priority(ssl->session, ctx->cipher_list) < 0 ||
        gnutls_compression_set_priority(ssl->session, ctx->comp_list) < 0 ||
        gnutls_protocol_set_priority(ssl->session, ctx->protocol_list) < 0||
        (ctx->certfiledh && read_dh_params(ssl->dhparams,
                           ctx->certfile) < 0) ||
        add_certificates(ssl->xcred, ctx->trustcerts) < 0 ||
#if 0
        add_certificates(ssl->xcred, ctx->certfile) < 0 ||
        add_certificates(ssl->xcred, ctx->dhcertfile) < 0 ||
#endif
        gnutls_credentials_set(ssl->session, GNUTLS_CRD_ANON,
                   ctx->isserver
                   ? (void *)ssl->anonservercred
                   : (void *)ssl->anonclientcred)
        < 0 ||
        gnutls_credentials_set(ssl->session, GNUTLS_CRD_CERTIFICATE,
                   ssl->xcred) < 0 ||

        gnutls_certificate_type_set_priority(ssl->session,
                         ctx->cert_list) < 0 ||
        (ctx->info_cpy.peer_verify_domain &&
         gnutls_server_name_set(ssl->session, GNUTLS_NAME_DNS,
                    ctx->info_cpy.peer_verify_domain,
                    strlen(ctx->info_cpy.peer_verify_domain))
         < 0)
        )
    {
        tls_free_session(ssl);
        return NULL;
    }

    if (ctx->certfiledh)
    {
        gnutls_certificate_set_dh_params(ssl->xcred, ssl->dhparams);

        gnutls_anon_set_server_dh_params(ssl->anonservercred,
                         ssl->dhparams);
    }

    if (ctx->isserver)
    {
        if (ctx->verify_cert)
            gnutls_certificate_server_set_request(ssl->session,
                                  ctx->fail_if_no_cert ?
                                  GNUTLS_CERT_REQUIRE:
                                  GNUTLS_CERT_REQUEST);
        gnutls_certificate_server_set_retrieve_function(ssl->xcred,
                                get_server_cert
                                );
    }
    else gnutls_certificate_client_set_retrieve_function(ssl->xcred,
                                 get_client_cert);

    gnutls_transport_set_ptr(ssl->session,(gnutls_transport_ptr_t)
                 GNUTLS_CAST_PTR_T fd);

    if (ssl->ctx->info_cpy.tlscache)
    {
        gnutls_db_set_ptr(ssl->session, ssl);

        gnutls_db_set_cache_expiration(ssl->session, 3600);

        gnutls_db_set_remove_function(ssl->session,
                          db_remove_func);
        gnutls_db_set_retrieve_function(ssl->session,
                        db_retrieve_func);
        gnutls_db_set_store_function(ssl->session,
                         db_store_func);
    }

    ssl->info_cpy.connect_interrupted=1;

    if (dohandshake(ssl, fd, NULL, NULL) < 0)
    {
        tls_disconnect(ssl, fd);
        return NULL;
    }

    return ssl;
}

void tls_disconnect(ssl_handle ssl, int fd)
{
    fcntl(fd, F_SETFL, 0);
    gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
    tls_free_session(ssl);
}

int    tls_transfer(struct tls_transfer_info *t, ssl_handle ssl, int fd,
             fd_set *r, fd_set *w)
{
    if (ssl->info_cpy.connect_interrupted)
    {
        if (dohandshake(ssl, fd, r, w) < 0)
            return -1;

        return 0;
    }

    if (t->shutdown)
        return -1;

    if (t->shutdown_interrupted)
    {
        while (chk_error(gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR),
                 ssl, fd, r, w, NULL))
            ;

        if ((r && FD_ISSET(fd, r)) ||
            (w && FD_ISSET(fd, w)))
        {
            return 1;
        }

            
        t->shutdown_interrupted=0;
        t->shutdown= -1;
        return -1;
    }

    if(0) printf("readleft=%d writeleft=%d\nread_interrupted=%d read_interrupted=%d\n",
            (int)t->readleft,(int)t->writeleft,
            t->read_interrupted,t->write_interrupted);

    if (!t->write_interrupted && t->readleft > 0 && t->writeleft == 0)
    {
        int rc;
        ssize_t n;

        do
        {
            n=gnutls_record_recv(ssl->session, t->readptr,
                         t->readleft);

            if (n >= 0)
            {
                if (n == 0)
                {
                    t->shutdown=1;
                    return -1;
                }

                t->readptr += n;
                t->readleft -= n;
                return 0;
            }

            if ((int)n == GNUTLS_E_REHANDSHAKE)
            {
                ssl->info_cpy.connect_interrupted=1;

                return tls_transfer(t, ssl, fd, r, w);
            }

        } while (chk_error((int)n, ssl, fd, r, w, &rc));

        if (rc < 0)
        {
            t->shutdown_interrupted=1;
            return tls_transfer(t, ssl, fd, r, w);
        }
    } else if (t->writeleft > 0)
    {
        int rc;
        ssize_t n;

        t->write_interrupted=0;

        do
        {
            n=gnutls_record_send(ssl->session, (void *)t->writeptr,
                         t->writeleft);

            if (n >= 0)
            {
                if (n == 0)
                {
                    t->shutdown=1;
                    return -1;
                }

                t->writeptr += n;
                t->writeleft -= n;
                return 0;
            }

            if ((int)n == GNUTLS_E_REHANDSHAKE)
            {
                t->write_interrupted=1;
                ssl->info_cpy.connect_interrupted=1;

                return tls_transfer(t, ssl, fd, r, w);
            }

        } while (chk_error((int)n, ssl, fd, r, w, &rc));

        if (rc < 0)
        {
            t->shutdown=1;
            return -1;
        }
        t->write_interrupted=1;
    }
    else
    {
        FD_SET(fd, r);
        FD_SET(fd, w);
    }
    return (1);
}

int tls_connecting(ssl_handle ssl)
{
    return ssl->info_cpy.connect_interrupted;
}

static const char *dump_dn(gnutls_x509_crt_t cert,
               int (*get_dn_func)(gnutls_x509_crt_t cert, int indx,
                          void *oid, size_t * sizeof_oid),
               int (*get_dnval_func)(gnutls_x509_crt_t cert,
                         const char *oid, int indx,
                         unsigned int raw_flag,
                         void *buf, size_t *sizeof_buf),
               void (*dump_func)(const char *, int cnt, void *),
               void *dump_arg)
{
    int idx;
    size_t bufsiz;
    size_t maxnamesize;
    size_t maxvalsize;
    char *oidname;
    char *oidval;
    int oidcnt;

    maxnamesize=0;
    maxvalsize=0;

    oidcnt=0;

    while (bufsiz=0, (*get_dn_func)(cert, oidcnt, NULL, &bufsiz)
           == GNUTLS_E_SHORT_MEMORY_BUFFER)
    {
        if (bufsiz > maxnamesize)
            maxnamesize=bufsiz;
        ++oidcnt;
    }

    oidname=malloc(maxnamesize);

    if (!oidname)
        return strerror(errno);

    for (idx=0; idx<oidcnt; ++idx)
    {
        int vidx;
        int rc;

        bufsiz=maxnamesize;

        if ((rc=(*get_dn_func)(cert, idx, oidname, &bufsiz)) < 0)
        {
            free(oidname);
            return gnutls_strerror(rc);
        }
    
        vidx=0;

        while (bufsiz=0,
               (*get_dnval_func)(cert, oidname, vidx, 0,
                     NULL, &bufsiz)
               == GNUTLS_E_SHORT_MEMORY_BUFFER)
        {
            if (bufsiz > maxvalsize)
                maxvalsize=bufsiz;
            ++vidx;
        }
    }

    oidval=malloc(maxvalsize);

    if (!oidval)
    {
        free(oidname);
        return strerror(errno);
    }

    for (idx=0; idx<oidcnt; ++idx)
    {
        int vidx;
        int rc;
        size_t i;
        const char *oidname_str;

        bufsiz=maxnamesize;

        if ((rc=(*get_dn_func)(cert, idx, oidname, &bufsiz)) < 0)
        {
            free(oidval);
            free(oidname);
            return gnutls_strerror(rc);
        }

        oidname_str=oidname;

        for (i=0; i<sizeof(oid_name_list)/sizeof(oid_name_list[0]);
             ++i)
        {
            if (strcmp(oid_name_list[i].oid, oidname) == 0)
            {
                oidname_str=oid_name_list[i].name;
                break;
            }
        }

        vidx=0;

        while (bufsiz=maxvalsize,
               (*get_dnval_func)(cert, oidname, vidx, 0,
                     oidval, &bufsiz) >= 0)
        {
            (*dump_func)("   ", -1, dump_arg);
            (*dump_func)(oidname_str, -1, dump_arg);
            (*dump_func)("=", -1, dump_arg);
            (*dump_func)(oidval, -1, dump_arg);
            (*dump_func)("\n", -1, dump_arg);
            ++vidx;
        }
    }
    
    free(oidval);
    free(oidname);
    return NULL;
}

static void print_time(const char *name, time_t t,
               void (*dump_func)(const char *, int cnt, void *),
               void *dump_arg)
{
    struct tm *tmptr=gmtime(&t);
    char buf[256];

    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tmptr);

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

static void tls_dump_connection_info_x509(ssl_handle ssl,
                      int server,
                      void (*dump_func)(const char *,
                                int cnt, void *),
                      void *dump_arg);

static void dump_cipher_name(gnutls_session_t session,
                 void (*dump_func)(const char *,
                           int cnt, void *),
                 void *dump_arg);

void tls_dump_connection_info(ssl_handle ssl,
                  int server,
                  void (*dump_func)(const char *, int cnt, void *),
                  void *dump_arg)
{
    if (gnutls_certificate_type_get (ssl->session) == GNUTLS_CRT_X509)
        tls_dump_connection_info_x509(ssl, server, dump_func,
                          dump_arg);

    (*dump_func)("Version: ", -1, dump_arg);
    (*dump_func)
        (gnutls_protocol_get_name(gnutls_protocol_get_version(ssl->session)),
         -1, dump_arg);
    (*dump_func)("\n", 1, dump_arg);

    {
        char buf[10];

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

        snprintf(buf, sizeof(buf), "%d", (int)
             gnutls_cipher_get_key_size(gnutls_cipher_get(ssl->session))
             *8);
        buf[sizeof(buf)-1]=0;

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

    (*dump_func)("Cipher: ", -1, dump_arg);
    dump_cipher_name(ssl->session, dump_func, dump_arg);
    (*dump_func)("\n", 1, dump_arg);
}

static void dump_cipher_name(gnutls_session_t session,
                 void (*dump_func)(const char *,
                           int cnt, void *),
                 void *dump_arg)
{
    gnutls_kx_algorithm_t kx_algo;
    gnutls_cipher_algorithm_t cipher_algo;
    gnutls_mac_algorithm_t mac_algo;
    const char *cipher_name;

    kx_algo=gnutls_kx_get(session);
    cipher_algo=gnutls_cipher_get(session);
    mac_algo=gnutls_mac_get(session);
    cipher_name=gnutls_cipher_suite_get_name(kx_algo, cipher_algo,
                         mac_algo);

    if (cipher_name)
        (*dump_func)(cipher_name, -1, dump_arg);
    else
    {
        gnutls_compression_method_t comp;

        (*dump_func)(gnutls_kx_get_name(kx_algo), -1, dump_arg);
        
        (*dump_func)("-", 1, dump_arg);
        (*dump_func)(gnutls_certificate_type_get_name(gnutls_certificate_type_get(session)),
                 -1, dump_arg);

        (*dump_func)("-", 1, dump_arg);
        (*dump_func)(gnutls_cipher_get_name(cipher_algo), -1,
                 dump_arg);

        if ((comp=gnutls_compression_get(session))
            != GNUTLS_COMP_NULL)
        {
            (*dump_func)("/", 1, dump_arg);
            (*dump_func)(gnutls_compression_get_name(comp),
                     -1, dump_arg);
        }

        (*dump_func)("-", 1, dump_arg);
        (*dump_func)(gnutls_mac_get_name(gnutls_mac_get(session)),
                 -1, dump_arg);
    }
}

static void tls_dump_connection_info_x509(ssl_handle ssl,
                      int server,
                      void (*dump_func)(const char *,
                                int cnt, void *),
                      void *dump_arg)
{
    const gnutls_datum_t *cert_list;
    unsigned int cert_list_size;
    gnutls_x509_crt_t *cert;

    cert_list=gnutls_certificate_get_peers(ssl->session, &cert_list_size);

    if (cert_list)
    {
        unsigned int i;

        cert=malloc(sizeof (*cert) * cert_list_size);

        for (i = 0; i<cert_list_size; i++)
        {
            gnutls_x509_crt_init(&cert[i]);
            gnutls_x509_crt_import(cert[i],
                           &cert_list[i],
                           GNUTLS_X509_FMT_DER);
        }

        for (i = 0; i < cert_list_size; i++)
        {
            time_t notbefore;
            time_t notafter;

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

            dump_dn(cert[i],
                gnutls_x509_crt_get_dn_oid,
                gnutls_x509_crt_get_dn_by_oid,
                dump_func, dump_arg);
            (*dump_func)("\n", 1, dump_arg);


#if 0
            (*dump_func)("Issuer:\n", -1, dump_arg);

            dump_dn(cert[i],
                gnutls_x509_crt_get_issuer_dn_oid,
                gnutls_x509_crt_get_issuer_dn_by_oid,
                dump_func, dump_arg);
            (*dump_func)("\n", 1, dump_arg);
#endif

            notbefore=gnutls_x509_crt_get_activation_time(cert[i]);
            notafter=gnutls_x509_crt_get_expiration_time(cert[i]);
            print_time("Not-Before", notbefore,
                   dump_func, dump_arg);
            print_time("Not-After",  notafter,
                   dump_func, dump_arg);
        }

        for (i = 0; i < cert_list_size; i++)
            gnutls_x509_crt_deinit(cert[i]);
        free(cert);
    }
}

static void gen_encryption_desc(gnutls_session_t session,
                void (*dump_func)(const char *,
                          int cnt, void *),
                void *dump_arg);

static void cnt_desc_size(const char *str, int s, void *ptr)
{
    if (s < 0)
        s=strlen(str);

    *(size_t *)ptr += s;
}

static void save_desc(const char *str, int s, void *ptr)
{
    if (s < 0)
        s=strlen(str);

    memcpy(*(char **)ptr, str, s);
    *(char **)ptr += s;
}

char *tls_get_encryption_desc(ssl_handle ssl)
{
    size_t n=1;
    char *buf;

    gen_encryption_desc(ssl->session, cnt_desc_size, &n);

    buf=malloc(n);

    if (buf)
    {
        char *ptr=buf;
        gen_encryption_desc(ssl->session, save_desc, &ptr);
        *ptr=0;
    }
    return buf;
}

static void gen_encryption_desc(gnutls_session_t session,
                void (*dump_func)(const char *,
                          int cnt, void *),
                void *dump_arg)
{
    char buf[10];

    (*dump_func)(gnutls_protocol_get_name(gnutls_protocol_get_version(session)),
             -1, dump_arg);
    (*dump_func)(",", 1, dump_arg);
    snprintf(buf, sizeof(buf), "%d",
         (int)gnutls_cipher_get_key_size(gnutls_cipher_get(session))
         *8);
    buf[sizeof(buf)-1]=0;
    (*dump_func)(buf, -1, dump_arg);
    (*dump_func)("bits,", -1, dump_arg);
    dump_cipher_name(session, dump_func, dump_arg);
}


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

int tls_validate_pem_cert(const char *buf, size_t buf_size)
{
    gnutls_datum_t dat;
    unsigned int cert_cnt=0;
     gnutls_x509_crt_t *certbuf;

    dat.data=(void *)buf;
    dat.size=buf_size;

    gnutls_x509_crt_list_import(NULL, &cert_cnt, &dat,
                    GNUTLS_X509_FMT_PEM,
                    GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);

    if (cert_cnt == 0)
        return 0;
    certbuf=malloc(sizeof(*certbuf)*cert_cnt);

    if (!certbuf)
        return 0;

    if (gnutls_x509_crt_list_import(certbuf, &cert_cnt, &dat,
                    GNUTLS_X509_FMT_PEM,
                    GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) < 0)
        return 0;

    while (cert_cnt)
        gnutls_x509_crt_deinit(certbuf[--cert_cnt]);
    free(certbuf);
    return (1);
}

char *tls_cert_name(const char *buf, size_t buf_size)
{
    gnutls_datum_t dat;
    unsigned int cert_cnt=0;
     gnutls_x509_crt_t *certbuf;
    char *p=0;
    size_t p_size;


    dat.data=(void *)buf;
    dat.size=buf_size;

    gnutls_x509_crt_list_import(NULL, &cert_cnt, &dat,
                    GNUTLS_X509_FMT_PEM,
                    GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);

    if (cert_cnt == 0)
        return 0;
    certbuf=malloc(sizeof(*certbuf)*cert_cnt);

    if (!certbuf)
        return 0;

    if (gnutls_x509_crt_list_import(certbuf, &cert_cnt, &dat,
                    GNUTLS_X509_FMT_PEM,
                    GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) < 0)
        return 0;

    p_size=0;
    gnutls_x509_crt_get_dn(certbuf[0], NULL, &p_size);
    ++p_size;
    p=malloc(p_size+1);

    if (p)
    {
        if (gnutls_x509_crt_get_dn(certbuf[0], p, &p_size)
            != GNUTLS_E_SUCCESS)
        {
            free(p);
            p=0;
        }
        else p[p_size]=0;
    }

    while (cert_cnt)
        gnutls_x509_crt_deinit(certbuf[--cert_cnt]);
    free(certbuf);
    return p;
}
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.1892 seconds