Back to index

courier  0.68.2
Classes | Defines | Functions
libcouriertls.c File Reference
#include "config.h"
#include "argparse.h"
#include "spipe.h"
#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"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>

Go to the source code of this file.

Classes

struct  walk_info

Defines

#define COURIERTCPD_EXPOSE_OPENSSL   1
#define dirent   direct
#define NAMLEN(dirent)   (dirent)->d_namlen
#define MAXDOMAINSIZE   256
#define N2(n)   ((asn1Time->data[n]-'0')*10 + asn1Time->data[(n)+1]-'0')
#define CPY(f, n)   (tm.f=N2(n))
#define PUTC(c)   if (q) *q++=(c); ++n

Functions

static const char * safe_getenv (const struct tls_info *info, const char *n)
static int get_peer_verify_level (const struct tls_info *info)
static int ssl_verify_callback (int goodcert, X509_STORE_CTX *x509)
static int verifypeer (const struct tls_info *info, SSL *ssl)
static RSA * rsa_callback (SSL *s, int export, int keylength)
static void nonsslerror (const struct tls_info *info, const char *pfix)
static void sslerror (const struct tls_info *info, const char *pfix, int rc)
static void init_session_cache (struct tls_info *, SSL_CTX *)
static int process_rsacertfile (SSL_CTX *ctx, const char *filename)
static int process_dhcertfile (SSL_CTX *ctx, const char *filename)
static int process_certfile (SSL_CTX *ctx, const char *certfile, const char *ip, int(*func)(SSL_CTX *, const char *))
static int client_cert_cb (ssl_handle ssl, X509 **x509, EVP_PKEY **pkey)
SSL_CTX * tls_create (int isserver, const struct tls_info *info)
void tls_destroy (SSL_CTX *ctx)
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 int get_func (void *rec, size_t recsize, int *doupdate, void *arg)
static int del_func (void *rec, size_t recsize, int *doupdate, void *arg)
SSL * tls_connect (SSL_CTX *ctx, int fd)
void tls_disconnect (SSL *ssl, int fd)
int tls_transfer (struct tls_transfer_info *t, SSL *ssl, int fd, fd_set *r, fd_set *w)
int tls_connecting (SSL *ssl)
int tls_certificate_verified (ssl_handle ssl)
static time_t asn1toTime (ASN1_TIME *asn1Time)
static void dump_x509 (X509 *x509, 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)
char * tls_get_encryption_desc (ssl_handle ssl)
int tls_validate_pem_cert (const char *buf, size_t buf_size)
static size_t conv_name_to_rfc2553 (const char *p, char *q)
char * tls_cert_name (const char *buf, size_t buf_size)

Class Documentation

struct walk_info

Definition at line 775 of file libcouriertls.c.

Class Members
int * copyflag
unsigned char * id
int id_len
time_t now
SSL_SESSION * ret

Define Documentation

Definition at line 8 of file libcouriertls.c.

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

Definition at line 28 of file libcouriertls.c.

#define MAXDOMAINSIZE   256

Definition at line 1214 of file libcouriertls.c.

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

Definition at line 29 of file libcouriertls.c.

#define PUTC (   c)    if (q) *q++=(c); ++n

Function Documentation

static time_t asn1toTime ( ASN1_TIME *  asn1Time) [static]

Definition at line 1216 of file libcouriertls.c.

{
       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;
}

Here is the caller graph for this function:

static int cache_add ( SSL *  ssl,
SSL_SESSION *  sess 
) [static]

Definition at line 736 of file libcouriertls.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void cache_del ( SSL_CTX *  ctx,
SSL_SESSION *  ssl 
) [static]

Definition at line 848 of file libcouriertls.c.

{
       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: ");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SSL_SESSION * cache_get ( SSL *  ssl,
unsigned char *  id,
int  id_len,
int *  copyflag 
) [static]

Definition at line 786 of file libcouriertls.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int client_cert_cb ( ssl_handle  ssl,
X509 **  x509,
EVP_PKEY **  pkey 
) [static]

Definition at line 372 of file libcouriertls.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static size_t conv_name_to_rfc2553 ( const char *  p,
char *  q 
) [static]

Definition at line 1481 of file libcouriertls.c.

{
#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;
}

Here is the caller graph for this function:

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

Definition at line 861 of file libcouriertls.c.

{
       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);
}

Here is the caller graph for this function:

static void dump_x509 ( X509 *  x509,
void(*)(const char *, int cnt, void *)  dump_func,
void *  dump_arg 
) [static]

Definition at line 1262 of file libcouriertls.c.

{
       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);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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

Definition at line 809 of file libcouriertls.c.

{
       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;
}

Here is the caller graph for this function:

static int get_peer_verify_level ( const struct tls_info info) [static]

Definition at line 70 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void init_session_cache ( struct tls_info info,
SSL_CTX *  ctx 
) [static]

Definition at line 704 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void nonsslerror ( const struct tls_info info,
const char *  pfix 
) [static]

Definition at line 227 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int process_certfile ( SSL_CTX *  ctx,
const char *  certfile,
const char *  ip,
int(*)(SSL_CTX *, const char *)  func 
) [static]

Definition at line 343 of file libcouriertls.c.

{
       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);
}

Here is the caller graph for this function:

static int process_dhcertfile ( SSL_CTX *  ctx,
const char *  filename 
) [static]

Definition at line 296 of file libcouriertls.c.

{
#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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int process_rsacertfile ( SSL_CTX *  ctx,
const char *  filename 
) [static]

Definition at line 272 of file libcouriertls.c.

{
#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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static RSA* rsa_callback ( SSL *  s,
int  export,
int  keylength 
) [static]

Definition at line 220 of file libcouriertls.c.

{
       return (RSA_generate_key(keylength,RSA_F4,NULL,NULL));
}

Here is the caller graph for this function:

static const char* safe_getenv ( const struct tls_info info,
const char *  n 
) [static]

Definition at line 62 of file libcouriertls.c.

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

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

Here is the caller graph for this function:

static int ssl_verify_callback ( int  goodcert,
X509_STORE_CTX *  x509 
) [static]

Definition at line 99 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sslerror ( const struct tls_info info,
const char *  pfix,
int  rc 
) [static]

Definition at line 239 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* tls_cert_name ( const char *  buf,
size_t  buf_size 
)

Definition at line 1521 of file libcouriertls.c.

{
       BIO *certbio;
       char *p, *q;
       X509 *x;
       size_t cnt;

       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;
}

Here is the call graph for this function:

Definition at line 1207 of file libcouriertls.c.

{
       struct tls_info *info=(struct tls_info *)SSL_get_app_data(ssl);

       return info->certificate_verified;
}
SSL* tls_connect ( SSL_CTX *  ctx,
int  fd 
)

Definition at line 897 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

int tls_connecting ( SSL *  ssl)

Definition at line 1200 of file libcouriertls.c.

{
       struct tls_info *info=(struct tls_info *)SSL_get_app_data(ssl);

       return info->accept_interrupted || info->connect_interrupted;
}
SSL_CTX* tls_create ( int  isserver,
const struct tls_info info 
)

Definition at line 480 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

void tls_destroy ( SSL_CTX *  ctx)

Definition at line 682 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

void tls_disconnect ( SSL *  ssl,
int  fd 
)

Definition at line 1015 of file libcouriertls.c.

{
       fcntl(fd, F_SETFL, 0);
       SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
       SSL_free(ssl);
       ERR_remove_state(0);
}
void tls_dump_connection_info ( ssl_handle  ssl,
int  server,
void(*)(const char *, int cnt, void *)  dump_func,
void *  dump_arg 
)

Definition at line 1341 of file libcouriertls.c.

{
       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);
              }
       }
}

Here is the call graph for this function:

Definition at line 1406 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

int tls_transfer ( struct tls_transfer_info t,
SSL *  ssl,
int  fd,
fd_set *  r,
fd_set *  w 
)

Definition at line 1025 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

int tls_validate_pem_cert ( const char *  buf,
size_t  buf_size 
)

Definition at line 1429 of file libcouriertls.c.

{
       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;
}

Here is the call graph for this function:

static int verifypeer ( const struct tls_info info,
SSL *  ssl 
) [static]

Definition at line 118 of file libcouriertls.c.

{
       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);
}

Here is the call graph for this function:

Here is the caller graph for this function: