Back to index

courier  0.68.2
libcouriergnutls.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2007-2009 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 #include      "config.h"
00006 #include      "argparse.h"
00007 #include      "spipe.h"
00008 #include      "libcouriertls.h"
00009 #include      "tlscache.h"
00010 #include      "soxwrap/soxwrap.h"
00011 #include      <gnutls/gnutls.h>
00012 #include      <gnutls/extra.h>
00013 #include      <gnutls/x509.h>
00014 #include      <gnutls/openpgp.h>
00015 #include      <stdio.h>
00016 #include      <string.h>
00017 #include      <stdlib.h>
00018 #include      <ctype.h>
00019 #include      <netdb.h>
00020 #if HAVE_DIRENT_H
00021 #include <dirent.h>
00022 #define NAMLEN(dirent) strlen((dirent)->d_name)
00023 #else
00024 #define dirent direct
00025 #define NAMLEN(dirent) (dirent)->d_namlen
00026 #if HAVE_SYS_NDIR_H
00027 #include <sys/ndir.h>
00028 #endif
00029 #if HAVE_SYS_DIR_H
00030 #include <sys/dir.h>
00031 #endif
00032 #if HAVE_NDIR_H
00033 #include <ndir.h>
00034 #endif
00035 #endif
00036 #if    HAVE_UNISTD_H
00037 #include      <unistd.h>
00038 #endif
00039 #if    HAVE_FCNTL_H
00040 #include      <fcntl.h>
00041 #endif
00042 #include      <errno.h>
00043 #if    HAVE_SYS_TYPES_H
00044 #include      <sys/types.h>
00045 #endif
00046 #if    HAVE_SYS_STAT_H
00047 #include      <sys/stat.h>
00048 #endif
00049 #include      <sys/socket.h>
00050 #include      <arpa/inet.h>
00051 
00052 #include      <sys/time.h>
00053 
00054 struct oid_name {
00055        const char *oid;
00056        const char *name;
00057 };
00058 
00059 static struct oid_name oid_name_list[]={
00060        {"2.5.4.0","objectClass"},
00061        {"2.5.4.2","knowledgeInformation"},
00062        {"2.5.4.3","cn"},
00063        {"2.5.4.4","sn"},
00064        {"2.5.4.5","serialNumber"},
00065        {"2.5.4.6","c"},
00066        {"2.5.4.7","l"},
00067        {"2.5.4.8","st"},
00068        {"2.5.4.9","street"},
00069        {"2.5.4.10","o"},
00070        {"2.5.4.11","ou"},
00071        {"2.5.4.12","title"},
00072        {"2.5.4.13","description"},
00073        {"2.5.4.14","searchGuide"},
00074        {"2.5.4.15","businessCategory"},
00075        {"2.5.4.16","postalAddress"},
00076        {"2.5.4.17","postalCode"},
00077        {"2.5.4.18","postOfficeBox"},
00078        {"2.5.4.19","physicalDeliveryOfficeName"},
00079        {"2.5.4.20","telephoneNumber"},
00080        {"2.5.4.21","telexNumber"},
00081        {"2.5.4.22","teletexTerminalIdentifier"},
00082        {"2.5.4.23","facsimileTelephoneNumber"},
00083        {"2.5.4.24","x121Address"},
00084        {"2.5.4.25","internationaliSDNNumber"},
00085        {"2.5.4.26","registeredAddress"},
00086        {"2.5.4.27","destinationIndicator"},
00087        {"2.5.4.28","preferredDeliveryMethod"},
00088        {"2.5.4.29","presentationAddress"},
00089        {"2.5.4.30","supportedApplicationContext"},
00090        {"2.5.4.31","member"},
00091        {"2.5.4.32","owner"},
00092        {"2.5.4.33","roleOccupant"},
00093        {"2.5.4.35","userPassword"},
00094        {"2.5.4.36","userCertificate"},
00095        {"2.5.4.37","cACertificate"},
00096        {"2.5.4.38","authorityRevocationList"},
00097        {"2.5.4.39","certificateRevocationList"},
00098        {"2.5.4.40","crossCertificatePair"},
00099        {"2.5.4.41","name"},
00100        {"2.5.4.42","givenName"},
00101        {"2.5.4.43","initials"},
00102        {"2.5.4.44","generationQualifier"},
00103        {"2.5.4.45","x500UniqueIdentifier"},
00104        {"2.5.4.46","dnQualifier"},
00105        {"2.5.4.47","enhancedSearchGuide"},
00106        {"2.5.4.48","protocolInformation"},
00107        {"2.5.4.49","distinguishedName"},
00108        {"2.5.4.50","uniqueMember"},
00109        {"2.5.4.51","houseIdentifier"},
00110        {"2.5.4.52","supportedAlgorithms"},
00111        {"2.5.4.53","deltaRevocationList"},
00112        {"2.5.4.54","dmdName"},
00113        {"2.5.4.65","pseudonym"},
00114        {"0.9.2342.19200300.100.1.3","mail"},
00115        {"0.9.2342.19200300.100.1.25","dc"},
00116        {"0.9.2342.19200300.100.1.1","uid"},
00117        {"1.3.6.1.1.3.1","uidObject"},
00118        {"1.2.840.113549.1.9.1","emailaddress"},
00119 };
00120 
00121 static const struct intmap {
00122        const char *name;
00123        int algo;
00124 } all_ciphers[]={
00125        { "AES256", GNUTLS_CIPHER_AES_256_CBC},
00126        { "3DES", GNUTLS_CIPHER_3DES_CBC },
00127        { "AES128", GNUTLS_CIPHER_AES_128_CBC},
00128        { "ARC128", GNUTLS_CIPHER_ARCFOUR_128 },
00129        { "ARC40", GNUTLS_CIPHER_ARCFOUR_40},
00130        { "RC2", GNUTLS_CIPHER_RC2_40_CBC},
00131        { "DES", GNUTLS_CIPHER_DES_CBC},
00132        { "NULL", GNUTLS_CIPHER_NULL },
00133        { NULL, 0},
00134 },
00135        all_kxs[]={
00136               { "DHERSA", GNUTLS_KX_DHE_RSA},
00137               { "DHEDSS", GNUTLS_KX_DHE_DSS},
00138               { "RSA", GNUTLS_KX_RSA},
00139               { "SRP", GNUTLS_KX_SRP},
00140               { "SRPRSA", GNUTLS_KX_SRP_RSA},
00141               { "SRPDSS", GNUTLS_KX_SRP_DSS},
00142               { "PSK", GNUTLS_KX_PSK},
00143               { "DHEPSK", GNUTLS_KX_DHE_PSK},
00144               { "ANONDH", GNUTLS_KX_ANON_DH},
00145               { "RSAEXPORT", GNUTLS_KX_RSA_EXPORT},
00146               { NULL, 0}
00147        }, all_comps[]={
00148               { "DEFLATE", GNUTLS_COMP_DEFLATE},
00149               { "LZO", GNUTLS_COMP_LZO},
00150               { "NULL", GNUTLS_COMP_NULL},
00151               { NULL, 0}
00152        }, all_certs[]={
00153               { "X509", GNUTLS_CRT_X509},
00154               { "OPENPGP", GNUTLS_CRT_OPENPGP},
00155               { NULL, 0}
00156        };
00157 
00158 struct ssl_context_t {
00159        int isserver;
00160        struct tls_info info_cpy;
00161        int *protocol_list;
00162        int cipher_list[sizeof(all_ciphers)/sizeof(all_ciphers[0])];
00163        int kx_list[sizeof(all_kxs)/sizeof(all_kxs[0])];
00164        int comp_list[sizeof(all_comps)/sizeof(all_comps[0])];
00165        int cert_list[sizeof(all_certs)/sizeof(all_certs[0])];
00166 
00167        char *certfile;
00168        int certfiledh;
00169 
00170        char *trustcerts;
00171 
00172        int verify_cert;
00173        int fail_if_no_cert;
00174 };
00175 
00176 struct ssl_handle_t {
00177        struct tls_info info_cpy;
00178        ssl_context ctx;
00179        gnutls_anon_client_credentials_t anonclientcred;
00180        gnutls_anon_server_credentials_t anonservercred;
00181        gnutls_certificate_credentials_t xcred;
00182        gnutls_dh_params_t dhparams;
00183        gnutls_session_t session;
00184 
00185        gnutls_x509_privkey x509_key;
00186 
00187        gnutls_openpgp_key_t pgp_crt;
00188        gnutls_openpgp_privkey_t pgp_key;
00189 };
00190 
00191 static void nonsslerror(struct tls_info *info, const char *pfix)
00192 {
00193         char errmsg[256];
00194 
00195         strcpy(errmsg, "couriertls: ");
00196         strncat(errmsg, pfix, 200);
00197         strcat(errmsg, ": ");
00198         strncat(errmsg, strerror(errno), 255 - strlen(errmsg));
00199 
00200         (*info->tls_err_msg)(errmsg, info->app_data);
00201 }
00202 
00203 static const char *safe_getenv(ssl_context context, const char *n,
00204                             const char *def)
00205 {
00206        const char *v=(*context->info_cpy.getconfigvar)
00207               (n, context->info_cpy.app_data);
00208 
00209        if (!v)       v="";
00210 
00211        if (!*v)
00212               v=def;
00213        return (v);
00214 }
00215 
00216 static char **splitwords(const char *var, size_t *nwords)
00217 {
00218        char *buf=strdup(var);
00219        char **ptrbuf;
00220 
00221        char *p;
00222        size_t cnt;
00223 
00224        char *saveptr;
00225 
00226        if (!buf)
00227               return NULL;
00228 
00229        cnt=1;
00230 
00231        for (p=buf; (p=strtok_r(p, ":", &saveptr)) != NULL; p=NULL)
00232               ++cnt;
00233 
00234        ptrbuf=malloc(cnt*sizeof(char *));
00235 
00236        if (!ptrbuf)
00237        {
00238               free(buf);
00239               return NULL;
00240        }
00241 
00242        cnt=0;
00243        strcpy(buf, var);
00244 
00245        for (p=buf; (p=strtok_r(p, ":", &saveptr)) != NULL; p=NULL)
00246        {
00247               ptrbuf[cnt++]=p;
00248 
00249               while (*p)
00250               {
00251                      if (*p == '-')
00252                             *p=' ';
00253                      ++p;
00254               }
00255        }
00256 
00257        ptrbuf[cnt]=0;
00258        if (cnt == 0)
00259               free(buf);
00260        *nwords=cnt;
00261 
00262        return ptrbuf;
00263 }
00264 
00265 static void splitwords_free(char **words)
00266 {
00267        if (words[0])
00268               free(words[0]);
00269        free(words);
00270 }
00271 
00272 static void addremove(int *cipher_list_out,
00273                     int removeit,
00274                     int n)
00275 {
00276        if (removeit)
00277        {
00278               int *p=cipher_list_out;
00279 
00280               while (*cipher_list_out)
00281               {
00282                      if (*cipher_list_out != n)
00283                             *p++ = *cipher_list_out;
00284                      ++cipher_list_out;
00285               }
00286               *p=0;
00287               return;
00288        }
00289 
00290        while (*cipher_list_out)
00291        {
00292               if (*cipher_list_out == n)
00293                      return;
00294               ++cipher_list_out;
00295        }
00296 
00297        *cipher_list_out++ =n;
00298        *cipher_list_out=0;
00299 }
00300 
00301 static void parse_map(const struct intmap *mapptr,
00302                     char **tokens,
00303                     int *tokens_out,
00304                     int is_ciphers)
00305 {
00306        size_t i;
00307 
00308        *tokens_out=0;
00309 
00310        for (i=0; tokens[i]; i++)
00311        {
00312               size_t j;
00313               int removeit=0;
00314               const char *name=tokens[i];
00315 
00316               if (*name == '-')
00317               {
00318                      ++name;
00319                      removeit=1;
00320               }
00321 
00322               for (j=0; mapptr[j].name; j++)
00323               {
00324                      if (strcmp(name, mapptr[j].name) == 0)
00325                      {
00326                             addremove(tokens_out, removeit,
00327                                      mapptr[j].algo);
00328                             continue;
00329                      }
00330 
00331                      if (is_ciphers && strcmp(name, "HIGH") == 0 &&
00332                          gnutls_cipher_get_key_size(mapptr[j].algo)
00333                                 > 128 / 8)
00334                      {
00335                             addremove(tokens_out, removeit,
00336                                      mapptr[j].algo);
00337                             continue;
00338                      }
00339 
00340                      if (is_ciphers && strcmp(name, "MEDIUM") == 0 &&
00341                          gnutls_cipher_get_key_size(mapptr[j].algo)
00342                                 == 128 / 8)
00343                      {
00344                             addremove(tokens_out, removeit,
00345                                      mapptr[j].algo);
00346                             continue;
00347                      }
00348 
00349                      if (is_ciphers && strcmp(name, "LOW") == 0 &&
00350                          gnutls_cipher_get_key_size(mapptr[j].algo)
00351                                 < 128 / 8 &&
00352                          gnutls_cipher_get_key_size(mapptr[j].algo)
00353                          > 0)
00354                      {
00355                             addremove(tokens_out, removeit,
00356                                      mapptr[j].algo);
00357                             continue;
00358                      }
00359 
00360                      if (strcmp(name, "ALL") == 0 &&
00361                          (!is_ciphers ||
00362                           gnutls_cipher_get_key_size(mapptr[j].algo)
00363                           > 0))
00364                      {
00365                             addremove(tokens_out, removeit,
00366                                      mapptr[j].algo);
00367                             continue;
00368                      }
00369               }
00370        }
00371 }
00372 
00373 ssl_context tls_create(int isserver, const struct tls_info *info)
00374 {
00375        static int first=1;
00376 
00377        char **words;
00378        size_t n, i;
00379        ssl_context p=malloc(sizeof(struct ssl_context_t));
00380        char *certfile=NULL, *dhcertfile=NULL;
00381 
00382        if (!p)
00383               return NULL;
00384 
00385        memset(p, 0, sizeof(*p));
00386 
00387        p->isserver=isserver;
00388        p->info_cpy=*info;
00389        p->info_cpy.certificate_verified=0;
00390 
00391        if (first)
00392        {
00393               if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL)
00394               {
00395                      fprintf(stderr, "GnuTLS version mismatch\n");
00396                      free(p);
00397                      errno=EINVAL;
00398                      return (NULL);
00399               }
00400 
00401               first=0;
00402 
00403               if (gnutls_global_init() < 0)
00404               {
00405                      fprintf(stderr, "gnutls_global_init() failed\n");
00406                      free(p);
00407                      errno=EINVAL;
00408                      return (NULL);
00409               }
00410 
00411               if (gnutls_global_init_extra() < 0)
00412               {
00413                      gnutls_global_deinit();
00414                      fprintf(stderr, "gnutls_global_init() failed\n");
00415                      free(p);
00416                      errno=EINVAL;
00417                      return (NULL);
00418               }
00419        }
00420 
00421        if (!(words=splitwords(safe_getenv(p, "TLS_PROTOCOL",
00422                                       "TLS1_1:TLS1:SSL3"), &n)))
00423        {
00424               tls_destroy(p);
00425               return NULL;
00426        }
00427 
00428        if ((p->protocol_list=malloc((n+1)*sizeof(int))) == NULL)
00429        {
00430               splitwords_free(words);
00431 
00432               tls_destroy(p);
00433               return NULL;
00434        }
00435 
00436        for (n=i=0; words[i]; ++i)
00437        {
00438               if (strcmp(words[i], "SSL3") == 0)
00439               {
00440                      p->protocol_list[n++]=GNUTLS_SSL3;
00441               }
00442               else if (strcmp(words[i], "TLS1") == 0)
00443               {
00444                      p->protocol_list[n++]=GNUTLS_TLS1_0;
00445               }
00446               else if (strcmp(words[i], "TLS1_1") == 0)
00447               {
00448                      p->protocol_list[n++]=GNUTLS_TLS1_1;
00449               }
00450        }
00451        p->protocol_list[n]=0;
00452 
00453        splitwords_free(words);
00454 
00455        if (!(words=splitwords(safe_getenv(p, "TLS_CIPHER_LIST",
00456                                       "HIGH:MEDIUM"), &n)))
00457        {
00458               tls_destroy(p);
00459               return NULL;
00460        }
00461 
00462        parse_map(all_ciphers, words, p->cipher_list, 1);
00463        splitwords_free(words);
00464 
00465        if (!(words=splitwords(safe_getenv(p, "TLS_KX_LIST", "ALL"), &n)))
00466        {
00467               tls_destroy(p);
00468               return NULL;
00469        }
00470 
00471        parse_map(all_kxs, words, p->kx_list, 0);
00472        splitwords_free(words);
00473 
00474        if (!(words=splitwords(safe_getenv(p, "TLS_COMPRESSION", "ALL"), &n)))
00475        {
00476               tls_destroy(p);
00477               return NULL;
00478        }
00479 
00480        parse_map(all_comps, words, p->comp_list, 0);
00481        splitwords_free(words);
00482 
00483        if (!(words=splitwords(safe_getenv(p, "TLS_CERTS", "X509"), &n)))
00484        {
00485               tls_destroy(p);
00486               return NULL;
00487        }
00488 
00489        parse_map(all_certs, words, p->cert_list, 0);
00490        splitwords_free(words);
00491 
00492 
00493        if ((certfile=strdup(safe_getenv(p, "TLS_CERTFILE", ""))) == NULL ||
00494            (dhcertfile=strdup(safe_getenv(p, "TLS_DHCERTFILE", "")))
00495            == NULL ||
00496            (p->trustcerts=strdup(safe_getenv(p, "TLS_TRUSTCERTS", "")))
00497            == NULL)
00498        {
00499               if (certfile)
00500                      free(certfile);
00501               if (dhcertfile)
00502                      free(dhcertfile);
00503               tls_destroy(p);
00504               return NULL;
00505        }
00506 
00507        if (*dhcertfile)
00508        {
00509               p->certfile=dhcertfile;
00510               p->certfiledh=1;
00511               dhcertfile=NULL;
00512        }
00513        else if (*certfile)
00514        {
00515               p->certfile=certfile;
00516               p->certfiledh=0;
00517               certfile=NULL;
00518        }
00519 
00520        if (certfile)
00521               free(certfile);
00522        if (dhcertfile)
00523               free(dhcertfile);
00524 
00525        switch (*safe_getenv(p, "TLS_VERIFYPEER", "P")) {
00526        case 'n':
00527        case 'N':
00528               p->verify_cert=0;
00529               p->fail_if_no_cert=0;
00530               break;
00531        case 'p':
00532        case 'P':            /* PEER */
00533               p->verify_cert=1;
00534               p->fail_if_no_cert=0;
00535               break;
00536        case 'r':
00537        case 'R':            /* REQUIREPEER */
00538               p->verify_cert=1;
00539               p->fail_if_no_cert=1;
00540               break;
00541        }
00542 
00543        if (info->peer_verify_domain)
00544               p->verify_cert=p->fail_if_no_cert=1;
00545 
00546        {
00547               const char *filename=safe_getenv(p, "TLS_CACHEFILE", "");
00548               const char *cachesize=safe_getenv(p, "TLS_CACHESIZE", "");
00549               off_t cachesize_l;
00550 
00551               if (filename && *filename)
00552               {
00553                      cachesize_l= cachesize ? (off_t)atol(cachesize):0;
00554 
00555                      if (cachesize_l <= 0)
00556                             cachesize_l=512L * 1024;
00557                      if ((p->info_cpy.tlscache=tls_cache_open(filename,
00558                                                          cachesize_l))
00559                          == NULL)
00560                      {
00561                             nonsslerror(&p->info_cpy, filename);
00562                             tls_destroy(p);
00563                             return NULL;
00564                      }
00565               }
00566        }
00567 
00568 #if 0
00569        int session_timeout=atoi(safe_getenv(ctx, "TLS_TIMEOUT"));
00570 #endif
00571        return p;
00572 }
00573 
00574 void tls_destroy(ssl_context p)
00575 {
00576        if (p->protocol_list)
00577               free(p->protocol_list);
00578 
00579        if (p->certfile)
00580               free(p->certfile);
00581 
00582        if (p->trustcerts)
00583               free(p->trustcerts);
00584 
00585        if (p->info_cpy.tlscache)
00586               tls_cache_close(p->info_cpy.tlscache);
00587        free(p);
00588 }
00589 
00590 int tls_certificate_verified(ssl_handle ssl)
00591 {
00592        return ssl->info_cpy.certificate_verified;
00593 }
00594 
00595 static int read_cert_dir(const char *cert_dir,
00596                       int (*cb_func)(const char *filename,
00597                                    struct stat *stat_buf,
00598                                    void *arg),
00599                       void *arg)
00600 {
00601        DIR *dirp;
00602        struct dirent *de;
00603        int rc=0;
00604 
00605        if ((dirp=opendir(cert_dir)) == NULL)
00606               return 0;
00607 
00608        while ((de=readdir(dirp)) != NULL)
00609        {
00610               char *buf;
00611               struct stat stat_buf;
00612 
00613               if (de->d_name[0] == '.')
00614                      continue;
00615 
00616               buf=malloc(strlen(cert_dir)+strlen(de->d_name)+2);
00617 
00618               if (!buf)
00619                      continue;
00620 
00621               strcat(strcat(strcpy(buf, cert_dir), "/"), de->d_name);
00622 
00623               if (lstat(buf, &stat_buf) < 0 || !S_ISREG(stat_buf.st_mode))
00624               {
00625                      free(buf);
00626                      continue;
00627               }
00628 
00629               rc=(*cb_func)(buf, &stat_buf, arg);
00630               free(buf);
00631               if (rc)
00632                      break;
00633        }
00634        closedir(dirp);
00635        return rc;
00636 }
00637 
00638 static int cnt_cert_size(const char *filename,
00639                       struct stat *stat_buf,
00640                       void *arg)
00641 {
00642        *(size_t *)arg += stat_buf->st_size;
00643        return 0;
00644 }
00645 
00646 struct cert_buf_ptr {
00647        char *ptr;
00648        size_t cnt;
00649 };
00650 
00651 static int save_cert_to_buf(const char *filename,
00652                          struct stat *stat_buf,
00653                          void *arg)
00654 {
00655        struct cert_buf_ptr *p=(struct cert_buf_ptr *)arg;
00656        FILE *fp;
00657 
00658        if (p->cnt < stat_buf->st_size)
00659               return 1;
00660 
00661        fp=fopen(filename, "r");
00662 
00663        if (fp)
00664        {
00665               if (stat_buf->st_size &&
00666                   fread(p->ptr, stat_buf->st_size, 1, fp) != 1)
00667               {
00668                      fclose(fp);
00669                      return 1;
00670               }
00671               fclose(fp);
00672        }
00673        p->ptr += stat_buf->st_size;
00674        p->cnt -= stat_buf->st_size;
00675        return 0;
00676 }
00677 
00678 
00679 static int add_certificates(gnutls_certificate_credentials_t xcred,
00680                          const char *certfile)
00681 {
00682        struct stat stat_buf;
00683        struct cert_buf_ptr ptr;
00684        gnutls_datum_t datum_ptr;
00685 
00686        if (!certfile || !*certfile || stat(certfile, &stat_buf) < 0)
00687               return 0;
00688 
00689        if (S_ISREG(stat_buf.st_mode))
00690        {
00691               return gnutls_certificate_set_x509_trust_file(xcred, certfile,
00692                                                        GNUTLS_X509_FMT_PEM);
00693        }
00694 
00695        if (!S_ISDIR(stat_buf.st_mode))
00696               return 0;
00697 
00698        ptr.cnt=0;
00699 
00700        if (read_cert_dir(certfile, cnt_cert_size, &ptr.cnt))
00701               return 0;
00702 
00703        datum_ptr.data=malloc(ptr.cnt+1);
00704        datum_ptr.size=ptr.cnt;
00705 
00706        if (!datum_ptr.data)
00707               return 0;
00708 
00709        ptr.ptr=(char *)datum_ptr.data;
00710 
00711        if (read_cert_dir(certfile, save_cert_to_buf, &ptr) ||
00712            ptr.cnt)
00713        {
00714               free(datum_ptr.data);
00715               return 0;
00716        }
00717        *ptr.ptr=0;
00718 
00719        gnutls_certificate_set_x509_trust_mem(xcred, &datum_ptr,
00720                                          GNUTLS_X509_FMT_PEM);
00721        free(datum_ptr.data);
00722 
00723        return 0;
00724 }
00725 
00726 static void tls_free_session_keys(ssl_handle ssl)
00727 {
00728        if (ssl->x509_key)
00729               gnutls_x509_privkey_deinit(ssl->x509_key);
00730 
00731        if (ssl->pgp_crt)
00732               gnutls_openpgp_key_deinit(ssl->pgp_crt);
00733 
00734        if (ssl->pgp_key)
00735               gnutls_openpgp_privkey_deinit(ssl->pgp_key);
00736 
00737        ssl->x509_key=NULL;
00738        ssl->pgp_crt=NULL;
00739        ssl->pgp_key=NULL;
00740 
00741 }
00742 
00743 static void tls_free_session(ssl_handle ssl)
00744 {
00745        gnutls_deinit(ssl->session);
00746        gnutls_certificate_free_credentials(ssl->xcred);
00747        gnutls_anon_free_client_credentials(ssl->anonclientcred);
00748        gnutls_anon_free_server_credentials(ssl->anonservercred);
00749        gnutls_dh_params_deinit(ssl->dhparams);
00750        tls_free_session_keys(ssl);
00751        free(ssl);
00752 }
00753 
00754 static int chk_error(int rc, ssl_handle ssl, int fd, fd_set *r, fd_set *w,
00755                    int *result_rc)
00756 {
00757        if (rc == GNUTLS_E_SUCCESS)
00758        {
00759               if (result_rc)
00760                      *result_rc=0;
00761               return 0;
00762        }
00763 
00764        if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED)
00765               return 1;
00766 
00767        if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED)
00768        {
00769               const char *alert=
00770                      gnutls_alert_get_name(gnutls_alert_get(ssl->session));
00771               (*ssl->info_cpy.tls_err_msg)(alert, ssl->info_cpy.app_data);
00772 
00773               if (result_rc)
00774                      *result_rc= -1;
00775               return 0;
00776        }
00777 
00778        if (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED)
00779        {
00780               fd_set *p=gnutls_record_get_direction(ssl->session)
00781                      ? w:r;
00782 
00783               if (p)
00784                      FD_SET(fd, p);
00785 
00786               if (result_rc)
00787                      *result_rc=1;
00788               return 0;
00789        }
00790 
00791        if (result_rc)
00792        {
00793               (*ssl->info_cpy.tls_err_msg)(gnutls_strerror(rc),
00794                                         ssl->info_cpy.app_data);
00795               *result_rc= -1;
00796        }
00797        return 0;
00798 }
00799 
00800 static int verify_client(ssl_handle ssl, int fd)
00801 {
00802        unsigned int status;
00803        int rc;
00804        const gnutls_datum_t *cert_list;
00805        unsigned int cert_list_size;
00806 
00807        if (!ssl->ctx->verify_cert)
00808               return 0;
00809 
00810        cert_list = gnutls_certificate_get_peers(ssl->session, &cert_list_size);
00811        if (cert_list == NULL || cert_list_size == 0)
00812        {
00813               if (ssl->ctx->fail_if_no_cert)
00814               {
00815                      (*ssl->info_cpy.tls_err_msg)
00816                             ("No certificate supplied by peer",
00817                              ssl->info_cpy.app_data);
00818                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00819               }
00820               return 0;
00821        }
00822 
00823        status=0;
00824        rc=gnutls_certificate_verify_peers2(ssl->session, &status);
00825 
00826        if (rc)
00827        {
00828               (*ssl->info_cpy.tls_err_msg)
00829                      ("Peer certificate verification failed",
00830                       ssl->info_cpy.app_data);
00831               return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00832        }
00833 
00834        if (status)
00835        {
00836               (*ssl->info_cpy.tls_err_msg)
00837                      (status & GNUTLS_CERT_REVOKED ?
00838                       "Peer's certificate is revoked":
00839                       status & GNUTLS_CERT_SIGNER_NOT_FOUND ?
00840                       "Peer's certificate not signed by a trusted authority":
00841                       status & GNUTLS_CERT_SIGNER_NOT_CA ?
00842                       "Invalid peer certificate authority":
00843                       status & GNUTLS_CERT_INSECURE_ALGORITHM ?
00844                       "Peer's certificate does not use a secure checksum":
00845                       "Invalid peer certificate",
00846                       ssl->info_cpy.app_data);
00847               return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00848        }
00849 
00850        if (gnutls_certificate_type_get(ssl->session) == GNUTLS_CRT_X509)
00851        {
00852               gnutls_x509_crt_t cert;
00853 
00854               if (gnutls_x509_crt_init(&cert) < 0)
00855               {
00856                      (*ssl->info_cpy.tls_err_msg)
00857                             ("Error initializing certificate",
00858                              ssl->info_cpy.app_data);
00859                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00860               }
00861 
00862               if (gnutls_x509_crt_import(cert, &cert_list[0],
00863                                       GNUTLS_X509_FMT_DER) < 0)
00864               {
00865                      (*ssl->info_cpy.tls_err_msg)
00866                             ("Error parsing certificate",
00867                              ssl->info_cpy.app_data);
00868                      gnutls_x509_crt_deinit (cert);
00869                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00870               }
00871 
00872 
00873               if (gnutls_x509_crt_get_expiration_time(cert) < time(NULL))
00874               {
00875                      (*ssl->info_cpy.tls_err_msg)
00876                             ("Expired certificate",
00877                              ssl->info_cpy.app_data);
00878                      gnutls_x509_crt_deinit (cert);
00879                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00880               }
00881 
00882               if (gnutls_x509_crt_get_activation_time(cert) > time(NULL))
00883               {
00884                      (*ssl->info_cpy.tls_err_msg)
00885                             ("Certificate not activated",
00886                              ssl->info_cpy.app_data);
00887                      gnutls_x509_crt_deinit (cert);
00888                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00889               }
00890 
00891               if (ssl->info_cpy.peer_verify_domain &&
00892                   *ssl->info_cpy.peer_verify_domain &&
00893                   !gnutls_x509_crt_check_hostname(cert,
00894                                               ssl->info_cpy
00895                                               .peer_verify_domain
00896                                               ))
00897               {
00898                      char hostname[256];
00899                      size_t hostname_size=sizeof(hostname);
00900                      const char *errmsg_txt="Certificate owner mismatch: ";
00901                      char *errmsg_buf;
00902 
00903                      if (gnutls_x509_crt_get_dn_by_oid(cert,
00904                                                    "2.5.4.3", 0,
00905                                                    0, hostname,
00906                                                    &hostname_size) < 0)
00907                             strcpy(hostname,"(unknown)");
00908 
00909                      errmsg_buf=malloc(strlen(errmsg_txt)+
00910                                      strlen(hostname)+10);
00911 
00912                      if (errmsg_buf)
00913                             strcat(strcpy(errmsg_buf, errmsg_txt),
00914                                    hostname);
00915 
00916                      (*ssl->info_cpy.tls_err_msg)
00917                             (errmsg_buf ? errmsg_buf: strerror(errno),
00918                              ssl->info_cpy.app_data);
00919                      gnutls_x509_crt_deinit (cert);
00920 
00921                      if (errmsg_buf)
00922                             free(errmsg_buf);
00923                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00924               }
00925 
00926               gnutls_x509_crt_deinit (cert);
00927        }
00928        else if (gnutls_certificate_type_get(ssl->session)==GNUTLS_CRT_OPENPGP)
00929        {
00930               gnutls_openpgp_key_t cert;
00931 
00932               if (gnutls_openpgp_key_init(&cert) < 0)
00933               {
00934                      (*ssl->info_cpy.tls_err_msg)
00935                             ("Error initializing certificate",
00936                              ssl->info_cpy.app_data);
00937                      gnutls_openpgp_key_deinit(cert);
00938                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00939               }
00940 
00941               if (gnutls_openpgp_key_import(cert, &cert_list[0],
00942                                          GNUTLS_OPENPGP_FMT_RAW) < 0)
00943               {
00944                      (*ssl->info_cpy.tls_err_msg)
00945                             ("Error parsing certificate",
00946                              ssl->info_cpy.app_data);
00947                      gnutls_openpgp_key_deinit (cert);
00948                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00949               }
00950 
00951               if (gnutls_openpgp_key_get_creation_time(cert) > time(NULL))
00952               {
00953                      (*ssl->info_cpy.tls_err_msg)
00954                             ("Certificate not activated",
00955                              ssl->info_cpy.app_data);
00956                      gnutls_openpgp_key_deinit (cert);
00957                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00958               }
00959 
00960               if (gnutls_openpgp_key_get_expiration_time(cert) < time(NULL))
00961               {
00962                      (*ssl->info_cpy.tls_err_msg)
00963                             ("Expired certificate",
00964                              ssl->info_cpy.app_data);
00965                      gnutls_openpgp_key_deinit (cert);
00966                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
00967               }
00968 
00969               if (ssl->info_cpy.peer_verify_domain &&
00970                   *ssl->info_cpy.peer_verify_domain &&
00971                   !gnutls_openpgp_key_check_hostname(cert,
00972                                                  ssl->info_cpy
00973                                                  .peer_verify_domain))
00974                                                 
00975               {
00976                      char *hostname;
00977                      size_t hostnamesiz=0;
00978                      const char *errmsg_txt=
00979                             "Certificate owner mismatch: ";
00980                      char *errmsg_buf;
00981 
00982                      gnutls_openpgp_key_get_name(cert, 0, NULL,
00983                                               &hostnamesiz);
00984 
00985                      hostname=malloc(hostnamesiz);
00986 
00987                      if (hostname)
00988                      {
00989                             *hostname=0;
00990                             gnutls_openpgp_key_get_name(cert,
00991                                                      0, hostname,
00992                                                      &hostnamesiz);
00993                      }
00994 
00995                      errmsg_buf=malloc(strlen(errmsg_txt)+
00996                                      strlen(hostname ?
00997                                            hostname:"")+100);
00998 
00999                      if (errmsg_buf)
01000                             strcat(strcpy(errmsg_buf, errmsg_txt),
01001                                           hostname ?
01002                                           hostname:"(unknown)");
01003 
01004                      (*ssl->info_cpy.tls_err_msg)
01005                             (errmsg_buf ? errmsg_buf:strerror(errno),
01006                              ssl->info_cpy.app_data);
01007                      if (errmsg_buf)
01008                             free(errmsg_buf);
01009                      if (hostname)
01010                             free(hostname);
01011                      gnutls_openpgp_key_deinit (cert);
01012                      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
01013               }
01014               gnutls_openpgp_key_deinit (cert);
01015        }
01016        else
01017        {
01018               (*ssl->info_cpy.tls_err_msg)
01019                      ("No certificate supplied by peer",
01020                       ssl->info_cpy.app_data);
01021               return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
01022        }
01023 
01024        ssl->info_cpy.certificate_verified=1;
01025        return 0;
01026 }
01027 
01028 static int dohandshake(ssl_handle ssl, int fd, fd_set *r, fd_set *w)
01029 {
01030        int rc;
01031 
01032        while (chk_error(gnutls_handshake(ssl->session),
01033                       ssl, fd, r, w, &rc))
01034               ;
01035 
01036        if (rc == 0)
01037        {
01038               ssl->info_cpy.connect_interrupted=0;
01039 
01040               
01041               if (verify_client(ssl, fd))
01042                      return -1;
01043 
01044               if (ssl->info_cpy.connect_callback != NULL &&
01045                   !(*ssl->info_cpy.connect_callback)(ssl,
01046                                                  ssl->info_cpy.app_data))
01047                      return (-1);
01048        }
01049        return rc;
01050 }
01051 
01052 static char *check_cert(const char *filename,
01053                      gnutls_certificate_type_t cert_type,
01054                      const char *req_dn,
01055                      int isvirtual)
01056 {
01057        if (!filename || !*filename)
01058               return NULL;
01059 
01060        while (*req_dn)
01061        {
01062               char *p=malloc(strlen(filename)+strlen(req_dn)+10);
01063 
01064               if (!p)
01065                      return NULL;
01066 
01067               strcat(strcat(strcpy(p, filename), "."), req_dn);
01068 
01069               if (cert_type == GNUTLS_CRT_OPENPGP)
01070                      strcat(p, ".pgp");
01071 
01072               if (access(p, R_OK) == 0)
01073                      return p;
01074 
01075               free(p);
01076 
01077               if (!isvirtual)
01078                      break;
01079 
01080               if ((req_dn=strchr(req_dn, '.')) == NULL)
01081                      break;
01082               ++req_dn;
01083        }
01084 
01085        {
01086               char *p=malloc(strlen(filename)+10);
01087 
01088               if (!p)
01089                      return NULL;
01090 
01091               strcpy(p, filename);
01092 
01093               if (cert_type == GNUTLS_CRT_OPENPGP)
01094                      strcat(p, ".pgp");
01095 
01096               if (access(p, R_OK) == 0)
01097                      return p;
01098 
01099               free(p);
01100        }
01101        return NULL;
01102 }
01103 
01104 static int read_file(const char *file,
01105                    gnutls_datum *filebuf)
01106 {
01107        FILE *fp;
01108        struct stat stat_buf;
01109 
01110        filebuf->data=NULL;
01111 
01112        if ((fp=fopen(file, "r")) == NULL ||
01113            fstat(fileno(fp), &stat_buf) < 0)
01114        {
01115               if (fp)
01116                      fclose(fp);
01117               return GNUTLS_E_FILE_ERROR;
01118        }
01119 
01120        if ((filebuf->data=malloc(stat_buf.st_size)) == NULL)
01121        {
01122               fclose(fp);
01123               return GNUTLS_E_MEMORY_ERROR;
01124        }
01125 
01126        if (fread(filebuf->data, filebuf->size=stat_buf.st_size, 1, fp) != 1)
01127        {
01128               if (fp)
01129                      fclose(fp);
01130               return GNUTLS_E_FILE_ERROR;
01131        }
01132        return 0;
01133 }
01134 
01135 static void release_file(gnutls_datum *filebuf)
01136 {
01137        if (filebuf->data)
01138               free(filebuf->data);
01139        filebuf->data=NULL;
01140 }
01141 
01142 static int set_cert(ssl_handle ssl,
01143                   gnutls_session_t session,
01144                   gnutls_retr_st *st,
01145                   const char *certfilename)
01146 {
01147        int rc;
01148        gnutls_datum filebuf;
01149        unsigned int cert_cnt;
01150 
01151        st->ncerts=0;
01152        st->deinit_all=0;
01153        tls_free_session_keys(ssl);
01154 
01155        if ((rc=read_file(certfilename, &filebuf)) < 0)
01156               return rc;
01157 
01158        switch (st->type) {
01159        case GNUTLS_CRT_X509:
01160 
01161               cert_cnt=0;
01162 
01163               if ((rc=gnutls_x509_privkey_init(&ssl->x509_key)) < 0 ||
01164                   (rc=gnutls_x509_privkey_import(ssl->x509_key, &filebuf,
01165                                              GNUTLS_X509_FMT_PEM)) < 0)
01166                      break;
01167 
01168               rc=gnutls_x509_crt_list_import(NULL, &cert_cnt,
01169                                           &filebuf,
01170                                           GNUTLS_X509_FMT_PEM,
01171                                           GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
01172 
01173               if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
01174                      break;
01175 
01176               st->ncerts=cert_cnt+1;
01177               st->cert.x509=gnutls_malloc(st->ncerts*sizeof(*st->cert.x509));
01178 
01179               rc=gnutls_x509_crt_list_import(st->cert.x509, &st->ncerts,
01180                                           &filebuf,
01181                                           GNUTLS_X509_FMT_PEM, 0);
01182 
01183               if (rc < 0)
01184               {
01185                      st->ncerts=0;
01186                      gnutls_free(st->cert.x509);
01187                      st->cert.x509=0;
01188                      break;
01189               }
01190               st->ncerts=rc;
01191               st->key.x509=ssl->x509_key;
01192               ssl->x509_key=0;
01193               st->deinit_all=1;
01194 
01195               break;
01196        case GNUTLS_CRT_OPENPGP:
01197               if ((rc=gnutls_openpgp_key_init(&ssl->pgp_crt)) < 0 ||
01198                   (rc=gnutls_openpgp_privkey_init(&ssl->pgp_key)) < 0 ||
01199                   (rc=gnutls_openpgp_key_import(ssl->pgp_crt, &filebuf,
01200                                             GNUTLS_OPENPGP_FMT_BASE64))
01201                   < 0 ||
01202                   (rc=gnutls_openpgp_privkey_import(ssl->pgp_key, &filebuf,
01203                                                 GNUTLS_OPENPGP_FMT_BASE64,
01204                                                 NULL, 0)) < 0)
01205                      break;
01206               st->cert.pgp=ssl->pgp_crt;
01207               st->ncerts=1;
01208               st->key.pgp=ssl->pgp_key;
01209               break;
01210        default:
01211               break;
01212        }
01213 
01214        release_file(&filebuf);
01215        return 0;
01216 }
01217 
01218 static int get_server_cert(gnutls_session_t session,
01219                         gnutls_retr_st *st)
01220 {
01221        ssl_handle ssl=(ssl_handle)gnutls_session_get_ptr(session);
01222        int vhost_idx;
01223        char *vhost_buf;
01224        size_t vhost_max_size=0;
01225        size_t vhost_size;
01226        unsigned int type=GNUTLS_NAME_DNS;
01227        char *certfilename=NULL;
01228        int rc;
01229 
01230        st->type=gnutls_certificate_type_get(session);
01231 
01232        for (vhost_idx=0; vhost_size=0,
01233                    gnutls_server_name_get(session, NULL, &vhost_size, &type,
01234                                        vhost_idx) ==
01235                    GNUTLS_E_SHORT_MEMORY_BUFFER; ++vhost_idx)
01236        {
01237               if (++vhost_size > vhost_max_size)
01238                      vhost_max_size=vhost_size;
01239        }
01240 
01241        vhost_buf=malloc(vhost_size);
01242 
01243        if (!vhost_buf)
01244               return GNUTLS_E_MEMORY_ERROR;
01245 
01246        for (vhost_idx=0; vhost_size=vhost_max_size,
01247                    gnutls_server_name_get(session, vhost_buf, &vhost_size,
01248                                        &type,
01249                                        vhost_idx) == GNUTLS_E_SUCCESS;
01250             ++vhost_idx)
01251        {
01252               if (ssl->ctx->certfile)
01253                      certfilename=check_cert(ssl->ctx->certfile,
01254                                           st->type,
01255                                           vhost_buf, 1);
01256 
01257               if (certfilename)
01258                      break;
01259        }
01260 
01261        if (!certfilename)
01262        {
01263               if (ssl->ctx->certfile)
01264                      certfilename=check_cert(ssl->ctx->certfile,
01265                                           st->type,
01266                                           safe_getenv(ssl->ctx,
01267                                                      "TCPLOCALIP", ""),
01268                                           0);
01269        }
01270 
01271        if (!certfilename)
01272               return 0;
01273 
01274        rc=set_cert(ssl, session, st, certfilename);
01275        free(certfilename);
01276        return rc;
01277 }
01278 
01279 
01280 static int pick_client_cert(gnutls_session_t session,
01281                          const gnutls_datum_t * req_ca_rdn, int nreqs,
01282                          const gnutls_pk_algorithm_t * sign_algos,
01283                          int sign_algos_length, gnutls_retr_st *st)
01284 {
01285        ssl_handle ssl=(ssl_handle)gnutls_session_get_ptr(session);
01286        int i, j;
01287        const char *cert_array;
01288        size_t cert_array_size;
01289        int rc=0;
01290 
01291        if (ssl->info_cpy.getpemclientcert4ca == NULL)
01292               return 0;
01293 
01294        if (st->type != GNUTLS_CRT_X509)
01295               return 0;
01296 
01297        if (ssl->info_cpy.loadpemclientcert4ca)
01298               (*ssl->info_cpy.loadpemclientcert4ca)(ssl->info_cpy.app_data);
01299 
01300        for (j=0; (*ssl->info_cpy.getpemclientcert4ca)(j, &cert_array,
01301                                                  &cert_array_size,
01302                                                  ssl->info_cpy.app_data);
01303             ++j)
01304        {
01305               gnutls_datum_t data;
01306               unsigned int cert_cnt=0;
01307               gnutls_x509_crt_t *certbuf;
01308               size_t issuer_buf_size=0;
01309               char *issuer_rdn;
01310               gnutls_x509_privkey pk;
01311 
01312               data.data=(unsigned char *)cert_array;
01313               data.size=cert_array_size;
01314               gnutls_x509_privkey_init(&pk);
01315               if (gnutls_x509_privkey_import(pk, &data,
01316                                           GNUTLS_X509_FMT_PEM)
01317                   != GNUTLS_E_SUCCESS)
01318               {
01319                      gnutls_x509_privkey_deinit(pk);
01320                      continue;
01321               }
01322 
01323               data.data=(void *)cert_array;
01324               data.size=cert_array_size;;
01325 
01326               gnutls_x509_crt_list_import(NULL, &cert_cnt, &data,
01327                                        GNUTLS_X509_FMT_PEM,
01328                                        GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
01329               if (cert_cnt == 0)
01330               {
01331                      gnutls_x509_privkey_deinit(pk);
01332                      continue;
01333               }
01334 
01335               certbuf=gnutls_malloc(sizeof(*certbuf)*cert_cnt);
01336 
01337               if (!certbuf)
01338               {
01339                      gnutls_x509_privkey_deinit(pk);
01340                      continue;
01341               }
01342 
01343               if (gnutls_x509_crt_list_import(certbuf, &cert_cnt, &data,
01344                                           GNUTLS_X509_FMT_PEM,
01345                                           GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) < 0)
01346               {
01347                      free(certbuf);
01348                      gnutls_x509_privkey_deinit(pk);
01349                      continue;
01350               }
01351 
01352 
01353               gnutls_x509_crt_get_issuer_dn(certbuf[0], NULL,
01354                                          &issuer_buf_size);
01355 
01356               ++issuer_buf_size;
01357 
01358               issuer_rdn=gnutls_malloc(issuer_buf_size+1);
01359 
01360               if (gnutls_x509_crt_get_issuer_dn(certbuf[0], issuer_rdn,
01361                                             &issuer_buf_size)
01362                   != GNUTLS_E_SUCCESS)
01363               {
01364                      gnutls_free(issuer_rdn);
01365                      issuer_rdn=0;
01366               }
01367               else
01368                      issuer_rdn[issuer_buf_size]=0;
01369 
01370               for (i=0; issuer_rdn && i<nreqs; i++)
01371               {
01372                      size_t buf_size=0;
01373                      char *ca_rdn;
01374 
01375                      gnutls_x509_rdn_get(&req_ca_rdn[i], NULL, &buf_size);
01376 
01377                      ++buf_size;
01378 
01379                      ca_rdn=gnutls_malloc(buf_size+1);
01380 
01381                      if (gnutls_x509_rdn_get(&req_ca_rdn[i], ca_rdn, &buf_size) !=
01382                          GNUTLS_E_SUCCESS)
01383                      {
01384                             gnutls_free(ca_rdn);
01385                             continue;
01386                      }
01387 
01388                      ca_rdn[buf_size]=0;
01389 
01390                      if (strcmp(ca_rdn, issuer_rdn) == 0)
01391                             break;
01392                      gnutls_free(ca_rdn);
01393               }
01394 
01395               st->ncerts=0;
01396               if (issuer_rdn && i < nreqs)
01397               {
01398                      st->cert.x509=certbuf;
01399                      st->ncerts=cert_cnt;
01400                      st->deinit_all=1;
01401                      st->key.x509=pk;
01402                      cert_cnt=0;
01403                      rc=1;
01404               }
01405               else
01406               {
01407                      gnutls_x509_privkey_deinit(pk);
01408                      while (cert_cnt)
01409                             gnutls_x509_crt_deinit(certbuf[--cert_cnt]);
01410                      gnutls_free(certbuf);
01411               }
01412               gnutls_free(issuer_rdn);
01413               if (rc)
01414                      break;
01415        }
01416 
01417        return rc;
01418 }
01419 
01420 static int get_client_cert(gnutls_session_t session,
01421                         const gnutls_datum_t * req_ca_rdn, int nreqs,
01422                         const gnutls_pk_algorithm_t * sign_algos,
01423                         int sign_algos_length, gnutls_retr_st *st)
01424 
01425 {
01426        ssl_handle ssl=(ssl_handle)gnutls_session_get_ptr(session);
01427        int rc;
01428        char *certfilename=NULL;
01429 
01430        rc= 0;
01431        st->type=gnutls_certificate_type_get(session);
01432 
01433        if (ssl->ctx->certfile)
01434               certfilename=check_cert(ssl->ctx->certfile,
01435                                    st->type, "", 0);
01436 
01437        st->ncerts=0;
01438        st->deinit_all=0;
01439 
01440        if (certfilename)
01441        {
01442               rc=set_cert(ssl, session, st, certfilename);
01443               free(certfilename);
01444        }
01445        else
01446        {
01447               rc=pick_client_cert(session, req_ca_rdn, nreqs, sign_algos,
01448                                 sign_algos_length, st);
01449               if (rc > 0)
01450                      rc=0;
01451        }
01452        return rc;
01453 }
01454 
01455 static int read_dh_params(gnutls_dh_params_t dhparams,
01456                        const char *filename)
01457 {
01458        int rc;
01459 
01460        gnutls_datum_t filebuf;
01461 
01462        rc=read_file(filename, &filebuf);
01463 
01464        if (rc == 0)
01465        {
01466               rc=gnutls_dh_params_import_pkcs3(dhparams, &filebuf,
01467                                            GNUTLS_X509_FMT_PEM);
01468               release_file(&filebuf);
01469        }
01470        return rc;
01471 }
01472 
01473 static int db_store_func(void *dummy, gnutls_datum_t key,
01474                       gnutls_datum_t data)
01475 {
01476        char *p=malloc(key.size + data.size + sizeof(int));
01477 
01478        if (!p)
01479               return -1;
01480 
01481        memcpy(p, &key.size, sizeof(key.size));
01482        memcpy(p+sizeof(key.size), key.data, key.size);
01483        memcpy(p+sizeof(key.size)+key.size, data.data, data.size);
01484 
01485        tls_cache_add(((ssl_handle)dummy)->info_cpy.tlscache, p,
01486                     key.size + data.size + sizeof(int));
01487        free(p);
01488        return 0;
01489 }
01490 
01491 static int do_cache_remove(void *rec, size_t recsize, int *doupdate, void *arg)
01492 {
01493        char *recptr=rec;
01494        gnutls_datum_t *key=(gnutls_datum_t *)arg;
01495 
01496        if (recsize >= key->size + sizeof(key->size))
01497        {
01498               gnutls_datum_t dummy;
01499 
01500               memcpy(&dummy.size, recptr, sizeof(dummy.size));
01501 
01502               if (dummy.size == key->size &&
01503                   memcmp(recptr + sizeof(key->size),
01504                         key->data, key->size) == 0)
01505               {
01506                      dummy.size= -1;
01507                      memcpy(recptr, &dummy.size, sizeof(dummy.size));
01508                      *doupdate=1;
01509                      return 1;
01510               }
01511        }
01512        return 0;
01513 }
01514        
01515 static int db_remove_func(void *dummy, gnutls_datum_t key)
01516 {
01517        tls_cache_walk(((ssl_handle)dummy)->info_cpy.tlscache,
01518                      do_cache_remove, &key);
01519        return 0;
01520 }
01521 
01522 struct db_retrieve_s {
01523        gnutls_datum_t ret;
01524        gnutls_datum_t *key;
01525 };
01526 
01527 static int do_cache_retrieve(void *rec, size_t recsize, int *doupdate,
01528                           void *arg)
01529 {
01530        char *recptr=rec;
01531        struct db_retrieve_s *ret=(struct db_retrieve_s *)arg;
01532 
01533        if (recsize >= ret->key->size + sizeof(ret->key->size))
01534        {
01535               gnutls_datum_t dummy;
01536 
01537               memcpy(&dummy.size, recptr, sizeof(dummy.size));
01538 
01539               if (dummy.size == ret->key->size &&
01540                   memcmp(recptr+sizeof(dummy.size),
01541                         ret->key->data,
01542                         ret->key->size) == 0)
01543               {
01544                      ret->ret.size=recsize-sizeof(dummy.size)-ret->key->size;
01545 
01546                      ret->ret.data=gnutls_malloc(ret->ret.size);
01547 
01548                      if (ret->ret.data)
01549                             memcpy(ret->ret.data,
01550                                    (void *)(recptr+sizeof(dummy.size)
01551                                           +ret->key->size),
01552                                    ret->ret.size);
01553                      else
01554                             ret->ret.size=0;
01555 
01556                      return 1;
01557               }
01558        }
01559        return 0;
01560 }
01561 
01562 static gnutls_datum_t db_retrieve_func(void *dummy, gnutls_datum_t key)
01563 {
01564        struct db_retrieve_s drs;
01565 
01566        drs.ret.data=NULL;
01567        drs.ret.size=0;
01568        drs.key= &key;
01569 
01570        tls_cache_walk(((ssl_handle)dummy)->info_cpy.tlscache,
01571                      do_cache_retrieve, &drs);
01572        return drs.ret;
01573 }
01574 
01575 ssl_handle tls_connect(ssl_context ctx, int fd)
01576 {
01577        ssl_handle ssl=malloc(sizeof(struct ssl_handle_t));
01578 
01579        if (!ssl)
01580               return NULL;
01581 
01582        memset(ssl, 0, sizeof(*ssl));
01583 
01584        ssl->info_cpy=ctx->info_cpy;
01585        ssl->ctx=ctx;
01586 
01587        if (ctx->info_cpy.peer_verify_domain && !*ctx->trustcerts)
01588        {
01589               errno=ENOENT;
01590               (*ctx->info_cpy.tls_err_msg)( "TLS_TRUSTCERTS not set",
01591                                          ctx->info_cpy.app_data);
01592               free(ssl);
01593               return NULL;
01594        }
01595 
01596         if (fcntl(fd, F_SETFL, O_NONBLOCK))
01597         {
01598                 nonsslerror(&ctx->info_cpy, "fcntl");
01599                 return (NULL);
01600         }
01601 
01602 #ifdef  SO_KEEPALIVE
01603 
01604         {
01605         int     dummy;
01606 
01607                 dummy=1;
01608 
01609                 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
01610                         (const char *)&dummy, sizeof(dummy)) < 0)
01611                 {
01612                         nonsslerror(&ctx->info_cpy, "setsockopt");
01613                         return (NULL);
01614                 }
01615         }
01616 #endif
01617 
01618 #ifdef  SO_LINGER
01619         {
01620         struct linger l;
01621 
01622                 l.l_onoff=0;
01623                 l.l_linger=0;
01624 
01625                 if (setsockopt(fd, SOL_SOCKET, SO_LINGER,
01626                         (const char *)&l, sizeof(l)) < 0)
01627                 {
01628                         nonsslerror(&ctx->info_cpy, "setsockopt");
01629                         return (NULL);
01630                 }
01631         }
01632 #endif
01633 
01634        if (gnutls_anon_allocate_client_credentials(&ssl->anonclientcred) < 0)
01635        {
01636               free(ssl);
01637               return NULL;
01638        }
01639 
01640        if (gnutls_anon_allocate_server_credentials(&ssl->anonservercred) < 0)
01641        {
01642               gnutls_anon_free_client_credentials(ssl->anonclientcred);
01643               free(ssl);
01644               return NULL;
01645        }
01646 
01647        if (gnutls_certificate_allocate_credentials(&ssl->xcred) < 0)
01648        {
01649               gnutls_anon_free_server_credentials(ssl->anonservercred);
01650               gnutls_anon_free_client_credentials(ssl->anonclientcred);
01651               free(ssl);
01652               return NULL;
01653        }
01654 
01655        if (gnutls_dh_params_init(&ssl->dhparams) < 0)
01656        {
01657               gnutls_certificate_free_credentials(ssl->xcred);
01658               gnutls_anon_free_server_credentials(ssl->anonservercred);
01659               gnutls_anon_free_client_credentials(ssl->anonclientcred);
01660               free(ssl);
01661               return NULL;
01662        }
01663 
01664        if (gnutls_init (&ssl->session,
01665                       ctx->isserver ? GNUTLS_SERVER:GNUTLS_CLIENT) < 0)
01666        {
01667               gnutls_certificate_free_credentials(ssl->xcred);
01668               gnutls_anon_free_server_credentials(ssl->anonservercred);
01669               gnutls_anon_free_client_credentials(ssl->anonclientcred);
01670               free(ssl);
01671               return NULL;
01672        }
01673 
01674        {
01675               const char *p=getenv("TLS_MIN_DH_BITS");
01676               unsigned int n=atoi(p ? p:"0");
01677 
01678               if (n)
01679                      gnutls_dh_set_prime_bits(ssl->session, n);
01680        }
01681 
01682        gnutls_session_set_ptr(ssl->session, ssl);
01683 
01684         gnutls_handshake_set_private_extensions(ssl->session, 1);
01685         gnutls_certificate_set_verify_flags(ssl->xcred, 
01686                                             GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT |
01687                                             
01688                                             /*
01689                                             GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
01690                                             GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_C
01691 RT |
01692 
01693                                             GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2 |
01694                                             GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5 |*/
01695                                             0);
01696 
01697         gnutls_certificate_set_verify_limits(ssl->xcred, 16384, 10);
01698 
01699        if (gnutls_set_default_priority (ssl->session) < 0 ||
01700            gnutls_kx_set_priority (ssl->session, ctx->kx_list) < 0 ||
01701            gnutls_cipher_set_priority(ssl->session, ctx->cipher_list) < 0 ||
01702            gnutls_compression_set_priority(ssl->session, ctx->comp_list) < 0 ||
01703            gnutls_protocol_set_priority(ssl->session, ctx->protocol_list) < 0||
01704            (ctx->certfiledh && read_dh_params(ssl->dhparams,
01705                                           ctx->certfile) < 0) ||
01706            add_certificates(ssl->xcred, ctx->trustcerts) < 0 ||
01707 #if 0
01708            add_certificates(ssl->xcred, ctx->certfile) < 0 ||
01709            add_certificates(ssl->xcred, ctx->dhcertfile) < 0 ||
01710 #endif
01711            gnutls_credentials_set(ssl->session, GNUTLS_CRD_ANON,
01712                                ctx->isserver
01713                                ? (void *)ssl->anonservercred
01714                                : (void *)ssl->anonclientcred)
01715            < 0 ||
01716            gnutls_credentials_set(ssl->session, GNUTLS_CRD_CERTIFICATE,
01717                                ssl->xcred) < 0 ||
01718 
01719            gnutls_certificate_type_set_priority(ssl->session,
01720                                            ctx->cert_list) < 0 ||
01721            (ctx->info_cpy.peer_verify_domain &&
01722             gnutls_server_name_set(ssl->session, GNUTLS_NAME_DNS,
01723                                 ctx->info_cpy.peer_verify_domain,
01724                                 strlen(ctx->info_cpy.peer_verify_domain))
01725             < 0)
01726            )
01727        {
01728               tls_free_session(ssl);
01729               return NULL;
01730        }
01731 
01732        if (ctx->certfiledh)
01733        {
01734               gnutls_certificate_set_dh_params(ssl->xcred, ssl->dhparams);
01735 
01736               gnutls_anon_set_server_dh_params(ssl->anonservercred,
01737                                            ssl->dhparams);
01738        }
01739 
01740        if (ctx->isserver)
01741        {
01742               if (ctx->verify_cert)
01743                      gnutls_certificate_server_set_request(ssl->session,
01744                                                        ctx->fail_if_no_cert ?
01745                                                        GNUTLS_CERT_REQUIRE:
01746                                                        GNUTLS_CERT_REQUEST);
01747               gnutls_certificate_server_set_retrieve_function(ssl->xcred,
01748                                                         get_server_cert
01749                                                         );
01750        }
01751        else gnutls_certificate_client_set_retrieve_function(ssl->xcred,
01752                                                       get_client_cert);
01753 
01754        gnutls_transport_set_ptr(ssl->session,(gnutls_transport_ptr_t)
01755                              GNUTLS_CAST_PTR_T fd);
01756 
01757        if (ssl->ctx->info_cpy.tlscache)
01758        {
01759               gnutls_db_set_ptr(ssl->session, ssl);
01760 
01761               gnutls_db_set_cache_expiration(ssl->session, 3600);
01762 
01763               gnutls_db_set_remove_function(ssl->session,
01764                                          db_remove_func);
01765               gnutls_db_set_retrieve_function(ssl->session,
01766                                           db_retrieve_func);
01767               gnutls_db_set_store_function(ssl->session,
01768                                         db_store_func);
01769        }
01770 
01771        ssl->info_cpy.connect_interrupted=1;
01772 
01773        if (dohandshake(ssl, fd, NULL, NULL) < 0)
01774        {
01775               tls_disconnect(ssl, fd);
01776               return NULL;
01777        }
01778 
01779        return ssl;
01780 }
01781 
01782 void tls_disconnect(ssl_handle ssl, int fd)
01783 {
01784        fcntl(fd, F_SETFL, 0);
01785        gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
01786        tls_free_session(ssl);
01787 }
01788 
01789 int    tls_transfer(struct tls_transfer_info *t, ssl_handle ssl, int fd,
01790                    fd_set *r, fd_set *w)
01791 {
01792        if (ssl->info_cpy.connect_interrupted)
01793        {
01794               if (dohandshake(ssl, fd, r, w) < 0)
01795                      return -1;
01796 
01797               return 0;
01798        }
01799 
01800        if (t->shutdown)
01801               return -1;
01802 
01803        if (t->shutdown_interrupted)
01804        {
01805               while (chk_error(gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR),
01806                              ssl, fd, r, w, NULL))
01807                      ;
01808 
01809               if ((r && FD_ISSET(fd, r)) ||
01810                   (w && FD_ISSET(fd, w)))
01811               {
01812                      return 1;
01813               }
01814 
01815                      
01816               t->shutdown_interrupted=0;
01817               t->shutdown= -1;
01818               return -1;
01819        }
01820 
01821        if(0) printf("readleft=%d writeleft=%d\nread_interrupted=%d read_interrupted=%d\n",
01822                   (int)t->readleft,(int)t->writeleft,
01823                   t->read_interrupted,t->write_interrupted);
01824 
01825        if (!t->write_interrupted && t->readleft > 0 && t->writeleft == 0)
01826        {
01827               int rc;
01828               ssize_t n;
01829 
01830               do
01831               {
01832                      n=gnutls_record_recv(ssl->session, t->readptr,
01833                                         t->readleft);
01834 
01835                      if (n >= 0)
01836                      {
01837                             if (n == 0)
01838                             {
01839                                    t->shutdown=1;
01840                                    return -1;
01841                             }
01842 
01843                             t->readptr += n;
01844                             t->readleft -= n;
01845                             return 0;
01846                      }
01847 
01848                      if ((int)n == GNUTLS_E_REHANDSHAKE)
01849                      {
01850                             ssl->info_cpy.connect_interrupted=1;
01851 
01852                             return tls_transfer(t, ssl, fd, r, w);
01853                      }
01854 
01855               } while (chk_error((int)n, ssl, fd, r, w, &rc));
01856 
01857               if (rc < 0)
01858               {
01859                      t->shutdown_interrupted=1;
01860                      return tls_transfer(t, ssl, fd, r, w);
01861               }
01862        } else if (t->writeleft > 0)
01863        {
01864               int rc;
01865               ssize_t n;
01866 
01867               t->write_interrupted=0;
01868 
01869               do
01870               {
01871                      n=gnutls_record_send(ssl->session, (void *)t->writeptr,
01872                                         t->writeleft);
01873 
01874                      if (n >= 0)
01875                      {
01876                             if (n == 0)
01877                             {
01878                                    t->shutdown=1;
01879                                    return -1;
01880                             }
01881 
01882                             t->writeptr += n;
01883                             t->writeleft -= n;
01884                             return 0;
01885                      }
01886 
01887                      if ((int)n == GNUTLS_E_REHANDSHAKE)
01888                      {
01889                             t->write_interrupted=1;
01890                             ssl->info_cpy.connect_interrupted=1;
01891 
01892                             return tls_transfer(t, ssl, fd, r, w);
01893                      }
01894 
01895               } while (chk_error((int)n, ssl, fd, r, w, &rc));
01896 
01897               if (rc < 0)
01898               {
01899                      t->shutdown=1;
01900                      return -1;
01901               }
01902               t->write_interrupted=1;
01903        }
01904        else
01905        {
01906               FD_SET(fd, r);
01907               FD_SET(fd, w);
01908        }
01909        return (1);
01910 }
01911 
01912 int tls_connecting(ssl_handle ssl)
01913 {
01914        return ssl->info_cpy.connect_interrupted;
01915 }
01916 
01917 static const char *dump_dn(gnutls_x509_crt_t cert,
01918                         int (*get_dn_func)(gnutls_x509_crt_t cert, int indx,
01919                                          void *oid, size_t * sizeof_oid),
01920                         int (*get_dnval_func)(gnutls_x509_crt_t cert,
01921                                            const char *oid, int indx,
01922                                            unsigned int raw_flag,
01923                                            void *buf, size_t *sizeof_buf),
01924                         void (*dump_func)(const char *, int cnt, void *),
01925                         void *dump_arg)
01926 {
01927        int idx;
01928        size_t bufsiz;
01929        size_t maxnamesize;
01930        size_t maxvalsize;
01931        char *oidname;
01932        char *oidval;
01933        int oidcnt;
01934 
01935        maxnamesize=0;
01936        maxvalsize=0;
01937 
01938        oidcnt=0;
01939 
01940        while (bufsiz=0, (*get_dn_func)(cert, oidcnt, NULL, &bufsiz)
01941               == GNUTLS_E_SHORT_MEMORY_BUFFER)
01942        {
01943               if (bufsiz > maxnamesize)
01944                      maxnamesize=bufsiz;
01945               ++oidcnt;
01946        }
01947 
01948        oidname=malloc(maxnamesize);
01949 
01950        if (!oidname)
01951               return strerror(errno);
01952 
01953        for (idx=0; idx<oidcnt; ++idx)
01954        {
01955               int vidx;
01956               int rc;
01957 
01958               bufsiz=maxnamesize;
01959 
01960               if ((rc=(*get_dn_func)(cert, idx, oidname, &bufsiz)) < 0)
01961               {
01962                      free(oidname);
01963                      return gnutls_strerror(rc);
01964               }
01965        
01966               vidx=0;
01967 
01968               while (bufsiz=0,
01969                      (*get_dnval_func)(cert, oidname, vidx, 0,
01970                                     NULL, &bufsiz)
01971                      == GNUTLS_E_SHORT_MEMORY_BUFFER)
01972               {
01973                      if (bufsiz > maxvalsize)
01974                             maxvalsize=bufsiz;
01975                      ++vidx;
01976               }
01977        }
01978 
01979        oidval=malloc(maxvalsize);
01980 
01981        if (!oidval)
01982        {
01983               free(oidname);
01984               return strerror(errno);
01985        }
01986 
01987        for (idx=0; idx<oidcnt; ++idx)
01988        {
01989               int vidx;
01990               int rc;
01991               size_t i;
01992               const char *oidname_str;
01993 
01994               bufsiz=maxnamesize;
01995 
01996               if ((rc=(*get_dn_func)(cert, idx, oidname, &bufsiz)) < 0)
01997               {
01998                      free(oidval);
01999                      free(oidname);
02000                      return gnutls_strerror(rc);
02001               }
02002 
02003               oidname_str=oidname;
02004 
02005               for (i=0; i<sizeof(oid_name_list)/sizeof(oid_name_list[0]);
02006                    ++i)
02007               {
02008                      if (strcmp(oid_name_list[i].oid, oidname) == 0)
02009                      {
02010                             oidname_str=oid_name_list[i].name;
02011                             break;
02012                      }
02013               }
02014 
02015               vidx=0;
02016 
02017               while (bufsiz=maxvalsize,
02018                      (*get_dnval_func)(cert, oidname, vidx, 0,
02019                                     oidval, &bufsiz) >= 0)
02020               {
02021                      (*dump_func)("   ", -1, dump_arg);
02022                      (*dump_func)(oidname_str, -1, dump_arg);
02023                      (*dump_func)("=", -1, dump_arg);
02024                      (*dump_func)(oidval, -1, dump_arg);
02025                      (*dump_func)("\n", -1, dump_arg);
02026                      ++vidx;
02027               }
02028        }
02029        
02030        free(oidval);
02031        free(oidname);
02032        return NULL;
02033 }
02034 
02035 static void print_time(const char *name, time_t t,
02036                      void (*dump_func)(const char *, int cnt, void *),
02037                      void *dump_arg)
02038 {
02039        struct tm *tmptr=gmtime(&t);
02040        char buf[256];
02041 
02042        strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tmptr);
02043 
02044        (*dump_func)(name, -1, dump_arg);
02045        (*dump_func)(": ", 2, dump_arg);
02046        (*dump_func)(buf, -1, dump_arg);
02047        (*dump_func)("\n", 1, dump_arg);
02048 }
02049 
02050 static void tls_dump_connection_info_x509(ssl_handle ssl,
02051                                      int server,
02052                                      void (*dump_func)(const char *,
02053                                                      int cnt, void *),
02054                                      void *dump_arg);
02055 
02056 static void dump_cipher_name(gnutls_session_t session,
02057                           void (*dump_func)(const char *,
02058                                           int cnt, void *),
02059                           void *dump_arg);
02060 
02061 void tls_dump_connection_info(ssl_handle ssl,
02062                            int server,
02063                            void (*dump_func)(const char *, int cnt, void *),
02064                            void *dump_arg)
02065 {
02066        if (gnutls_certificate_type_get (ssl->session) == GNUTLS_CRT_X509)
02067               tls_dump_connection_info_x509(ssl, server, dump_func,
02068                                          dump_arg);
02069 
02070        (*dump_func)("Version: ", -1, dump_arg);
02071        (*dump_func)
02072               (gnutls_protocol_get_name(gnutls_protocol_get_version(ssl->session)),
02073                -1, dump_arg);
02074        (*dump_func)("\n", 1, dump_arg);
02075 
02076        {
02077               char buf[10];
02078 
02079               (*dump_func)("Bits: ", -1, dump_arg);
02080 
02081               snprintf(buf, sizeof(buf), "%d", (int)
02082                       gnutls_cipher_get_key_size(gnutls_cipher_get(ssl->session))
02083                       *8);
02084               buf[sizeof(buf)-1]=0;
02085 
02086               (*dump_func)(buf, -1, dump_arg);
02087               (*dump_func)("\n", 1, dump_arg);
02088        }
02089 
02090        (*dump_func)("Cipher: ", -1, dump_arg);
02091        dump_cipher_name(ssl->session, dump_func, dump_arg);
02092        (*dump_func)("\n", 1, dump_arg);
02093 }
02094 
02095 static void dump_cipher_name(gnutls_session_t session,
02096                           void (*dump_func)(const char *,
02097                                           int cnt, void *),
02098                           void *dump_arg)
02099 {
02100        gnutls_kx_algorithm_t kx_algo;
02101        gnutls_cipher_algorithm_t cipher_algo;
02102        gnutls_mac_algorithm_t mac_algo;
02103        const char *cipher_name;
02104 
02105        kx_algo=gnutls_kx_get(session);
02106        cipher_algo=gnutls_cipher_get(session);
02107        mac_algo=gnutls_mac_get(session);
02108        cipher_name=gnutls_cipher_suite_get_name(kx_algo, cipher_algo,
02109                                            mac_algo);
02110 
02111        if (cipher_name)
02112               (*dump_func)(cipher_name, -1, dump_arg);
02113        else
02114        {
02115               gnutls_compression_method_t comp;
02116 
02117               (*dump_func)(gnutls_kx_get_name(kx_algo), -1, dump_arg);
02118               
02119               (*dump_func)("-", 1, dump_arg);
02120               (*dump_func)(gnutls_certificate_type_get_name(gnutls_certificate_type_get(session)),
02121                           -1, dump_arg);
02122 
02123               (*dump_func)("-", 1, dump_arg);
02124               (*dump_func)(gnutls_cipher_get_name(cipher_algo), -1,
02125                           dump_arg);
02126 
02127               if ((comp=gnutls_compression_get(session))
02128                   != GNUTLS_COMP_NULL)
02129               {
02130                      (*dump_func)("/", 1, dump_arg);
02131                      (*dump_func)(gnutls_compression_get_name(comp),
02132                                  -1, dump_arg);
02133               }
02134 
02135               (*dump_func)("-", 1, dump_arg);
02136               (*dump_func)(gnutls_mac_get_name(gnutls_mac_get(session)),
02137                           -1, dump_arg);
02138        }
02139 }
02140 
02141 static void tls_dump_connection_info_x509(ssl_handle ssl,
02142                                      int server,
02143                                      void (*dump_func)(const char *,
02144                                                      int cnt, void *),
02145                                      void *dump_arg)
02146 {
02147        const gnutls_datum_t *cert_list;
02148        unsigned int cert_list_size;
02149        gnutls_x509_crt_t *cert;
02150 
02151        cert_list=gnutls_certificate_get_peers(ssl->session, &cert_list_size);
02152 
02153        if (cert_list)
02154        {
02155               unsigned int i;
02156 
02157               cert=malloc(sizeof (*cert) * cert_list_size);
02158 
02159               for (i = 0; i<cert_list_size; i++)
02160               {
02161                      gnutls_x509_crt_init(&cert[i]);
02162                      gnutls_x509_crt_import(cert[i],
02163                                           &cert_list[i],
02164                                           GNUTLS_X509_FMT_DER);
02165               }
02166 
02167               for (i = 0; i < cert_list_size; i++)
02168               {
02169                      time_t notbefore;
02170                      time_t notafter;
02171 
02172                      (*dump_func)("Subject:\n", -1, dump_arg);
02173 
02174                      dump_dn(cert[i],
02175                             gnutls_x509_crt_get_dn_oid,
02176                             gnutls_x509_crt_get_dn_by_oid,
02177                             dump_func, dump_arg);
02178                      (*dump_func)("\n", 1, dump_arg);
02179 
02180 
02181 #if 0
02182                      (*dump_func)("Issuer:\n", -1, dump_arg);
02183 
02184                      dump_dn(cert[i],
02185                             gnutls_x509_crt_get_issuer_dn_oid,
02186                             gnutls_x509_crt_get_issuer_dn_by_oid,
02187                             dump_func, dump_arg);
02188                      (*dump_func)("\n", 1, dump_arg);
02189 #endif
02190 
02191                      notbefore=gnutls_x509_crt_get_activation_time(cert[i]);
02192                      notafter=gnutls_x509_crt_get_expiration_time(cert[i]);
02193                      print_time("Not-Before", notbefore,
02194                                dump_func, dump_arg);
02195                      print_time("Not-After",  notafter,
02196                                dump_func, dump_arg);
02197               }
02198 
02199               for (i = 0; i < cert_list_size; i++)
02200                      gnutls_x509_crt_deinit(cert[i]);
02201               free(cert);
02202        }
02203 }
02204 
02205 static void gen_encryption_desc(gnutls_session_t session,
02206                             void (*dump_func)(const char *,
02207                                             int cnt, void *),
02208                             void *dump_arg);
02209 
02210 static void cnt_desc_size(const char *str, int s, void *ptr)
02211 {
02212        if (s < 0)
02213               s=strlen(str);
02214 
02215        *(size_t *)ptr += s;
02216 }
02217 
02218 static void save_desc(const char *str, int s, void *ptr)
02219 {
02220        if (s < 0)
02221               s=strlen(str);
02222 
02223        memcpy(*(char **)ptr, str, s);
02224        *(char **)ptr += s;
02225 }
02226 
02227 char *tls_get_encryption_desc(ssl_handle ssl)
02228 {
02229        size_t n=1;
02230        char *buf;
02231 
02232        gen_encryption_desc(ssl->session, cnt_desc_size, &n);
02233 
02234        buf=malloc(n);
02235 
02236        if (buf)
02237        {
02238               char *ptr=buf;
02239               gen_encryption_desc(ssl->session, save_desc, &ptr);
02240               *ptr=0;
02241        }
02242        return buf;
02243 }
02244 
02245 static void gen_encryption_desc(gnutls_session_t session,
02246                             void (*dump_func)(const char *,
02247                                             int cnt, void *),
02248                             void *dump_arg)
02249 {
02250        char buf[10];
02251 
02252        (*dump_func)(gnutls_protocol_get_name(gnutls_protocol_get_version(session)),
02253                    -1, dump_arg);
02254        (*dump_func)(",", 1, dump_arg);
02255        snprintf(buf, sizeof(buf), "%d",
02256                (int)gnutls_cipher_get_key_size(gnutls_cipher_get(session))
02257                *8);
02258        buf[sizeof(buf)-1]=0;
02259        (*dump_func)(buf, -1, dump_arg);
02260        (*dump_func)("bits,", -1, dump_arg);
02261        dump_cipher_name(session, dump_func, dump_arg);
02262 }
02263 
02264 
02265 /* ------------------- */
02266 
02267 int tls_validate_pem_cert(const char *buf, size_t buf_size)
02268 {
02269        gnutls_datum_t dat;
02270        unsigned int cert_cnt=0;
02271        gnutls_x509_crt_t *certbuf;
02272 
02273        dat.data=(void *)buf;
02274        dat.size=buf_size;
02275 
02276        gnutls_x509_crt_list_import(NULL, &cert_cnt, &dat,
02277                                 GNUTLS_X509_FMT_PEM,
02278                                 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
02279 
02280        if (cert_cnt == 0)
02281               return 0;
02282        certbuf=malloc(sizeof(*certbuf)*cert_cnt);
02283 
02284        if (!certbuf)
02285               return 0;
02286 
02287        if (gnutls_x509_crt_list_import(certbuf, &cert_cnt, &dat,
02288                                    GNUTLS_X509_FMT_PEM,
02289                                    GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) < 0)
02290               return 0;
02291 
02292        while (cert_cnt)
02293               gnutls_x509_crt_deinit(certbuf[--cert_cnt]);
02294        free(certbuf);
02295        return (1);
02296 }
02297 
02298 char *tls_cert_name(const char *buf, size_t buf_size)
02299 {
02300        gnutls_datum_t dat;
02301        unsigned int cert_cnt=0;
02302        gnutls_x509_crt_t *certbuf;
02303        char *p=0;
02304        size_t p_size;
02305 
02306 
02307        dat.data=(void *)buf;
02308        dat.size=buf_size;
02309 
02310        gnutls_x509_crt_list_import(NULL, &cert_cnt, &dat,
02311                                 GNUTLS_X509_FMT_PEM,
02312                                 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
02313 
02314        if (cert_cnt == 0)
02315               return 0;
02316        certbuf=malloc(sizeof(*certbuf)*cert_cnt);
02317 
02318        if (!certbuf)
02319               return 0;
02320 
02321        if (gnutls_x509_crt_list_import(certbuf, &cert_cnt, &dat,
02322                                    GNUTLS_X509_FMT_PEM,
02323                                    GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) < 0)
02324               return 0;
02325 
02326        p_size=0;
02327        gnutls_x509_crt_get_dn(certbuf[0], NULL, &p_size);
02328        ++p_size;
02329        p=malloc(p_size+1);
02330 
02331        if (p)
02332        {
02333               if (gnutls_x509_crt_get_dn(certbuf[0], p, &p_size)
02334                   != GNUTLS_E_SUCCESS)
02335               {
02336                      free(p);
02337                      p=0;
02338               }
02339               else p[p_size]=0;
02340        }
02341 
02342        while (cert_cnt)
02343               gnutls_x509_crt_deinit(certbuf[--cert_cnt]);
02344        free(certbuf);
02345        return p;
02346 }