Back to index

citadel  8.12
serv_crypto.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1987-2012 by the citadel.org team
00003  *
00004  *  This program is open source software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License version 3.
00006  *  
00007  *  
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  
00015  *  
00016  *  
00017  */
00018 
00019 #include <string.h>
00020 #include <unistd.h>
00021 #include <sys/stat.h>
00022 #include <sys/types.h>
00023 #include "sysdep.h"
00024 
00025 #ifdef HAVE_OPENSSL
00026 #include <openssl/ssl.h>
00027 #include <openssl/err.h>
00028 #include <openssl/rand.h>
00029 #endif
00030 
00031 #if TIME_WITH_SYS_TIME
00032 # include <sys/time.h>
00033 # include <time.h>
00034 #else
00035 # if HAVE_SYS_TIME_H
00036 #  include <sys/time.h>
00037 # else
00038 #  include <time.h>
00039 # endif
00040 #endif
00041 
00042 #ifdef HAVE_PTHREAD_H
00043 #include <pthread.h>
00044 #endif
00045 
00046 #ifdef HAVE_SYS_SELECT_H
00047 #include <sys/select.h>
00048 #endif
00049 
00050 #include <stdio.h>
00051 #include <libcitadel.h>
00052 #include "server.h"
00053 #include "serv_crypto.h"
00054 #include "sysdep_decls.h"
00055 #include "citadel.h"
00056 #include "config.h"
00057 
00058 
00059 #include "ctdl_module.h"
00060 /* TODO: should we use the standard module init stuff to start this? */
00061 /* TODO: should we register an event handler to call destruct_ssl? */
00062 
00063 #ifdef HAVE_OPENSSL
00064 SSL_CTX *ssl_ctx;           /* SSL context */
00065 pthread_mutex_t **SSLCritters;     /* Things needing locking */
00066 
00067 static unsigned long id_callback(void)
00068 {
00069        return (unsigned long) pthread_self();
00070 }
00071 
00072 void destruct_ssl(void)
00073 {
00074        int a;
00075        for (a = 0; a < CRYPTO_num_locks(); a++) 
00076               free(SSLCritters[a]);
00077        free (SSLCritters);
00078 }
00079 
00080 void init_ssl(void)
00081 {
00082        const SSL_METHOD *ssl_method;
00083        DH *dh;
00084        RSA *rsa=NULL;
00085        X509_REQ *req = NULL;
00086        X509 *cer = NULL;
00087        EVP_PKEY *pk = NULL;
00088        EVP_PKEY *req_pkey = NULL;
00089        X509_NAME *name = NULL;
00090        FILE *fp;
00091 
00092        if (!access(EGD_POOL, F_OK))
00093               RAND_egd(EGD_POOL);
00094 
00095        if (!RAND_status()) {
00096               syslog(LOG_CRIT,
00097                      "PRNG not adequately seeded, won't do SSL/TLS\n");
00098               return;
00099        }
00100        SSLCritters =
00101            malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t *));
00102        if (!SSLCritters) {
00103               syslog(LOG_EMERG, "citserver: can't allocate memory!!\n");
00104               /* Nothing's been initialized, just die */
00105               exit(1);
00106        } else {
00107               int a;
00108 
00109               for (a = 0; a < CRYPTO_num_locks(); a++) {
00110                      SSLCritters[a] = malloc(sizeof(pthread_mutex_t));
00111                      if (!SSLCritters[a]) {
00112                             syslog(LOG_EMERG,
00113                                    "citserver: can't allocate memory!!\n");
00114                             /* Nothing's been initialized, just die */
00115                             exit(1);
00116                      }
00117                      pthread_mutex_init(SSLCritters[a], NULL);
00118               }
00119        }
00120 
00121        /*
00122         * Initialize SSL transport layer
00123         */
00124        SSL_library_init();
00125        SSL_load_error_strings();
00126        ssl_method = SSLv23_server_method();
00127        if (!(ssl_ctx = SSL_CTX_new(ssl_method))) {
00128               syslog(LOG_CRIT, "SSL_CTX_new failed: %s\n",
00129                      ERR_reason_error_string(ERR_get_error()));
00130               return;
00131        }
00132        if (!(SSL_CTX_set_cipher_list(ssl_ctx, CIT_CIPHERS))) {
00133               syslog(LOG_CRIT, "SSL: No ciphers available\n");
00134               SSL_CTX_free(ssl_ctx);
00135               ssl_ctx = NULL;
00136               return;
00137        }
00138 #if 0
00139 #if SSLEAY_VERSION_NUMBER >= 0x00906000L
00140        SSL_CTX_set_mode(ssl_ctx, SSL_CTX_get_mode(ssl_ctx) |
00141                       SSL_MODE_AUTO_RETRY);
00142 #endif
00143 #endif
00144 
00145        CRYPTO_set_locking_callback(ssl_lock);
00146        CRYPTO_set_id_callback(id_callback);
00147 
00148        /* Load DH parameters into the context */
00149        dh = DH_new();
00150        if (!dh) {
00151               syslog(LOG_CRIT, "init_ssl() can't allocate a DH object: %s\n",
00152                      ERR_reason_error_string(ERR_get_error()));
00153               SSL_CTX_free(ssl_ctx);
00154               ssl_ctx = NULL;
00155               return;
00156        }
00157        if (!(BN_hex2bn(&(dh->p), DH_P))) {
00158               syslog(LOG_CRIT, "init_ssl() can't assign DH_P: %s\n",
00159                      ERR_reason_error_string(ERR_get_error()));
00160               SSL_CTX_free(ssl_ctx);
00161               ssl_ctx = NULL;
00162               return;
00163        }
00164        if (!(BN_hex2bn(&(dh->g), DH_G))) {
00165               syslog(LOG_CRIT, "init_ssl() can't assign DH_G: %s\n",
00166                      ERR_reason_error_string(ERR_get_error()));
00167               SSL_CTX_free(ssl_ctx);
00168               ssl_ctx = NULL;
00169               return;
00170        }
00171        dh->length = DH_L;
00172        SSL_CTX_set_tmp_dh(ssl_ctx, dh);
00173        DH_free(dh);
00174 
00175        /* Get our certificates in order.
00176         * First, create the key/cert directory if it's not there already...
00177         */
00178        mkdir(ctdl_key_dir, 0700);
00179 
00180        /*
00181         * Generate a key pair if we don't have one.
00182         */
00183        if (access(file_crpt_file_key, R_OK) != 0) {
00184               syslog(LOG_INFO, "Generating RSA key pair.\n");
00185               rsa = RSA_generate_key(1024,       /* modulus size */
00186                                    65537, /* exponent */
00187                                    NULL,  /* no callback */
00188                                    NULL); /* no callback */
00189               if (rsa == NULL) {
00190                      syslog(LOG_CRIT, "Key generation failed: %s\n",
00191                             ERR_reason_error_string(ERR_get_error()));
00192               }
00193               if (rsa != NULL) {
00194                      fp = fopen(file_crpt_file_key, "w");
00195                      if (fp != NULL) {
00196                             chmod(file_crpt_file_key, 0600);
00197                             if (PEM_write_RSAPrivateKey(fp,    /* the file */
00198                                                  rsa,   /* the key */
00199                                                  NULL,  /* no enc */
00200                                                  NULL,  /* no passphr */
00201                                                  0,     /* no passphr */
00202                                                  NULL,  /* no callbk */
00203                                                  NULL   /* no callbk */
00204                             ) != 1) {
00205                                    syslog(LOG_CRIT, "Cannot write key: %s\n",
00206                                           ERR_reason_error_string(ERR_get_error()));
00207                                    unlink(file_crpt_file_key);
00208                             }
00209                             fclose(fp);
00210                      }
00211                      RSA_free(rsa);
00212               }
00213        }
00214 
00215        /*
00216         * If there is no certificate file on disk, we will be generating a self-signed certificate
00217         * in the next step.  Therefore, if we have neither a CSR nor a certificate, generate
00218         * the CSR in this step so that the next step may commence.
00219         */
00220        if ( (access(file_crpt_file_cer, R_OK) != 0) && (access(file_crpt_file_csr, R_OK) != 0) ) {
00221               syslog(LOG_INFO, "Generating a certificate signing request.\n");
00222 
00223               /*
00224                * Read our key from the file.  No, we don't just keep this
00225                * in memory from the above key-generation function, because
00226                * there is the possibility that the key was already on disk
00227                * and we didn't just generate it now.
00228                */
00229               fp = fopen(file_crpt_file_key, "r");
00230               if (fp) {
00231                      rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
00232                      fclose(fp);
00233               }
00234 
00235               if (rsa) {
00236 
00237                      /* Create a public key from the private key */
00238                      if (pk=EVP_PKEY_new(), pk != NULL) {
00239                             EVP_PKEY_assign_RSA(pk, rsa);
00240                             if (req = X509_REQ_new(), req != NULL) {
00241 
00242                                    /* Set the public key */
00243                                    X509_REQ_set_pubkey(req, pk);
00244                                    X509_REQ_set_version(req, 0L);
00245 
00246                                    name = X509_REQ_get_subject_name(req);
00247 
00248                                    /* Tell it who we are */
00249 
00250                                    /*
00251                                    X509_NAME_add_entry_by_txt(name, "C",
00252                                           MBSTRING_ASC, "US", -1, -1, 0);
00253 
00254                                    X509_NAME_add_entry_by_txt(name, "ST",
00255                                           MBSTRING_ASC, "New York", -1, -1, 0);
00256 
00257                                    X509_NAME_add_entry_by_txt(name, "L",
00258                                           MBSTRING_ASC, "Mount Kisco", -1, -1, 0);
00259                                    */
00260 
00261                                    X509_NAME_add_entry_by_txt(name, "O",
00262                                                            MBSTRING_ASC, 
00263                                                            (unsigned char*) config.c_humannode,
00264                                                            -1, -1, 0);
00265 
00266                                    X509_NAME_add_entry_by_txt(name, "OU",
00267                                                            MBSTRING_ASC, 
00268                                                            (unsigned const char*)"Citadel server",
00269                                                            -1, -1, 0);
00270 
00271                                    /* X509_NAME_add_entry_by_txt(name, "CN",
00272                                           MBSTRING_ASC, config.c_fqdn, -1, -1, 0);
00273                                    */
00274 
00275                                    X509_NAME_add_entry_by_txt(name, 
00276                                                            "CN",
00277                                                            MBSTRING_ASC, 
00278                                                            (const unsigned char *)"*", -1, -1, 0);
00279                             
00280                                    X509_REQ_set_subject_name(req, name);
00281 
00282                                    /* Sign the CSR */
00283                                    if (!X509_REQ_sign(req, pk, EVP_md5())) {
00284                                           syslog(LOG_CRIT, "X509_REQ_sign(): error\n");
00285                                    }
00286                                    else {
00287                                           /* Write it to disk. */     
00288                                           fp = fopen(file_crpt_file_csr, "w");
00289                                           if (fp != NULL) {
00290                                                  chmod(file_crpt_file_csr, 0600);
00291                                                  PEM_write_X509_REQ(fp, req);
00292                                                  fclose(fp);
00293                                           }
00294                                    }
00295 
00296                                    X509_REQ_free(req);
00297                             }
00298                      }
00299 
00300                      RSA_free(rsa);
00301               }
00302 
00303               else {
00304                      syslog(LOG_CRIT, "Unable to read private key.\n");
00305               }
00306        }
00307 
00308 
00309 
00310        /*
00311         * Generate a self-signed certificate if we don't have one.
00312         */
00313        if (access(file_crpt_file_cer, R_OK) != 0) {
00314               syslog(LOG_INFO, "Generating a self-signed certificate.\n");
00315 
00316               /* Same deal as before: always read the key from disk because
00317                * it may or may not have just been generated.
00318                */
00319               fp = fopen(file_crpt_file_key, "r");
00320               if (fp) {
00321                      rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
00322                      fclose(fp);
00323               }
00324 
00325               /* This also holds true for the CSR. */
00326               req = NULL;
00327               cer = NULL;
00328               pk = NULL;
00329               if (rsa) {
00330                      if (pk=EVP_PKEY_new(), pk != NULL) {
00331                             EVP_PKEY_assign_RSA(pk, rsa);
00332                      }
00333 
00334                      fp = fopen(file_crpt_file_csr, "r");
00335                      if (fp) {
00336                             req = PEM_read_X509_REQ(fp, NULL, NULL, NULL);
00337                             fclose(fp);
00338                      }
00339 
00340                      if (req) {
00341                             if (cer = X509_new(), cer != NULL) {
00342 
00343                                    ASN1_INTEGER_set(X509_get_serialNumber(cer), 0);
00344                                    X509_set_issuer_name(cer, req->req_info->subject);
00345                                    X509_set_subject_name(cer, req->req_info->subject);
00346                                    X509_gmtime_adj(X509_get_notBefore(cer),0);
00347                                    X509_gmtime_adj(X509_get_notAfter(cer),(long)60*60*24*SIGN_DAYS);
00348                                    req_pkey = X509_REQ_get_pubkey(req);
00349                                    X509_set_pubkey(cer, req_pkey);
00350                                    EVP_PKEY_free(req_pkey);
00351                                    
00352                                    /* Sign the cert */
00353                                    if (!X509_sign(cer, pk, EVP_md5())) {
00354                                           syslog(LOG_CRIT, "X509_sign(): error\n");
00355                                    }
00356                                    else {
00357                                           /* Write it to disk. */     
00358                                           fp = fopen(file_crpt_file_cer, "w");
00359                                           if (fp != NULL) {
00360                                                  chmod(file_crpt_file_cer, 0600);
00361                                                  PEM_write_X509(fp, cer);
00362                                                  fclose(fp);
00363                                           }
00364                                    }
00365                                    X509_free(cer);
00366                             }
00367                      }
00368 
00369                      RSA_free(rsa);
00370               }
00371        }
00372 
00373 
00374        /*
00375         * Now try to bind to the key and certificate.
00376         */
00377         SSL_CTX_use_certificate_chain_file(ssl_ctx, file_crpt_file_cer);
00378         SSL_CTX_use_PrivateKey_file(ssl_ctx, file_crpt_file_key, SSL_FILETYPE_PEM);
00379         if ( !SSL_CTX_check_private_key(ssl_ctx) ) {
00380               syslog(LOG_CRIT, "Cannot install certificate: %s\n",
00381                             ERR_reason_error_string(ERR_get_error()));
00382         }
00383 
00384        /* Finally let the server know we're here */
00385        CtdlRegisterProtoHook(cmd_stls, "STLS", "Start SSL/TLS session");
00386        CtdlRegisterProtoHook(cmd_gtls, "GTLS",
00387                            "Get SSL/TLS session status");
00388        CtdlRegisterSessionHook(endtls, EVT_STOP, PRIO_STOP + 10);
00389 }
00390 
00391 
00392 /*
00393  * client_write_ssl() Send binary data to the client encrypted.
00394  */
00395 void client_write_ssl(const char *buf, int nbytes)
00396 {
00397        int retval;
00398        int nremain;
00399        char junk[1];
00400 
00401        nremain = nbytes;
00402 
00403        while (nremain > 0) {
00404               if (SSL_want_write(CC->ssl)) {
00405                      if ((SSL_read(CC->ssl, junk, 0)) < 1) {
00406                             syslog(LOG_DEBUG, "SSL_read in client_write: %s\n", ERR_reason_error_string(ERR_get_error()));
00407                      }
00408               }
00409               retval =
00410                   SSL_write(CC->ssl, &buf[nbytes - nremain], nremain);
00411               if (retval < 1) {
00412                      long errval;
00413 
00414                      errval = SSL_get_error(CC->ssl, retval);
00415                      if (errval == SSL_ERROR_WANT_READ ||
00416                          errval == SSL_ERROR_WANT_WRITE) {
00417                             sleep(1);
00418                             continue;
00419                      }
00420                      syslog(LOG_DEBUG, "SSL_write got error %ld, ret %d\n", errval, retval);
00421                      if (retval == -1)
00422                             syslog(LOG_DEBUG, "errno is %d\n", errno);
00423                      endtls();
00424                      client_write(&buf[nbytes - nremain], nremain);
00425                      return;
00426               }
00427               nremain -= retval;
00428        }
00429 }
00430 
00431 
00432 /*
00433  * read data from the encrypted layer.
00434  */
00435 int client_read_sslbuffer(StrBuf *buf, int timeout)
00436 {
00437        char sbuf[16384]; /* OpenSSL communicates in 16k blocks, so let's speak its native tongue. */
00438        int rlen;
00439        char junk[1];
00440        SSL *pssl = CC->ssl;
00441 
00442        if (pssl == NULL) return(-1);
00443 
00444        while (1) {
00445               if (SSL_want_read(pssl)) {
00446                      if ((SSL_write(pssl, junk, 0)) < 1) {
00447                             syslog(LOG_DEBUG, "SSL_write in client_read\n");
00448                      }
00449               }
00450               rlen = SSL_read(pssl, sbuf, sizeof(sbuf));
00451               if (rlen < 1) {
00452                      long errval;
00453 
00454                      errval = SSL_get_error(pssl, rlen);
00455                      if (errval == SSL_ERROR_WANT_READ || errval == SSL_ERROR_WANT_WRITE) {
00456                             sleep(1);
00457                             continue;
00458                      }
00459                      syslog(LOG_DEBUG, "SSL_read got error %ld\n", errval);
00460                      endtls();
00461                      return (-1);
00462               }
00463               StrBufAppendBufPlain(buf, sbuf, rlen, 0);
00464               return rlen;
00465        }
00466        return (0);
00467 }
00468 
00469 int client_readline_sslbuffer(StrBuf *Line, StrBuf *IOBuf, const char **Pos, int timeout)
00470 {
00471        CitContext *CCC = CC;
00472        const char *pos = NULL;
00473        const char *pLF;
00474        int len, rlen;
00475        int nSuccessLess = 0;
00476        const char *pch = NULL;
00477        
00478        if ((Line == NULL) ||
00479            (Pos == NULL) ||
00480            (IOBuf == NULL))
00481        {
00482               if (Pos != NULL)
00483                      *Pos = NULL;
00484 //            *Error = ErrRBLF_PreConditionFailed;
00485               return -1;
00486        }
00487 
00488        pos = *Pos;
00489        if ((StrLength(IOBuf) > 0) && 
00490            (pos != NULL) && 
00491            (pos < ChrPtr(IOBuf) + StrLength(IOBuf))) 
00492        {
00493               pch = pos;
00494               pch = strchr(pch, '\n');
00495               
00496               if (pch == NULL) {
00497                      StrBufAppendBufPlain(Line, pos, 
00498                                         StrLength(IOBuf) - (pos - ChrPtr(IOBuf)), 0);
00499                      FlushStrBuf(IOBuf);
00500                      *Pos = NULL;
00501               }
00502               else {
00503                      int n = 0;
00504                      if ((pch > ChrPtr(IOBuf)) && 
00505                          (*(pch - 1) == '\r')) {
00506                             n = 1;
00507                      }
00508                      StrBufAppendBufPlain(Line, pos, 
00509                                         (pch - pos - n), 0);
00510 
00511                      if (StrLength(IOBuf) <= (pch - ChrPtr(IOBuf) + 1)) {
00512                             FlushStrBuf(IOBuf);
00513                             *Pos = NULL;
00514                      }
00515                      else 
00516                             *Pos = pch + 1;
00517                      return StrLength(Line);
00518               }
00519        }
00520 
00521        pLF = NULL;
00522        while ((nSuccessLess < timeout) && 
00523               (pLF == NULL) &&
00524               (CCC->ssl != NULL)) {
00525 
00526               rlen = client_read_sslbuffer(IOBuf, timeout);
00527               if (rlen < 1) {
00528 //                   *Error = strerror(errno);
00529 //                   close(*fd);
00530 //                   *fd = -1;
00531                      return -1;
00532               }
00533               else if (rlen > 0) {
00534                      pLF = strchr(ChrPtr(IOBuf), '\n');
00535               }
00536        }
00537        *Pos = NULL;
00538        if (pLF != NULL) {
00539               pos = ChrPtr(IOBuf);
00540               len = pLF - pos;
00541               if (len > 0 && (*(pLF - 1) == '\r') )
00542                      len --;
00543               StrBufAppendBufPlain(Line, pos, len, 0);
00544               if (pLF + 1 >= ChrPtr(IOBuf) + StrLength(IOBuf))
00545               {
00546                      FlushStrBuf(IOBuf);
00547               }
00548               else 
00549                      *Pos = pLF + 1;
00550               return StrLength(Line);
00551        }
00552 //     *Error = ErrRBLF_NotEnoughSentFromServer;
00553        return -1;
00554 }
00555 
00556 
00557 
00558 int client_read_sslblob(StrBuf *Target, long bytes, int timeout)
00559 {
00560        long baselen;
00561        long RemainRead;
00562        int retval = 0;
00563        CitContext *CCC = CC;
00564 
00565        baselen = StrLength(Target);
00566 
00567        if (StrLength(CCC->RecvBuf.Buf) > 0)
00568        {
00569               long RemainLen;
00570               long TotalLen;
00571               const char *pchs;
00572 
00573               if (CCC->RecvBuf.ReadWritePointer == NULL)
00574                      CCC->RecvBuf.ReadWritePointer = ChrPtr(CCC->RecvBuf.Buf);
00575               pchs = ChrPtr(CCC->RecvBuf.Buf);
00576               TotalLen = StrLength(CCC->RecvBuf.Buf);
00577               RemainLen = TotalLen - (pchs - CCC->RecvBuf.ReadWritePointer);
00578               if (RemainLen > bytes)
00579                      RemainLen = bytes;
00580               if (RemainLen > 0)
00581               {
00582                      StrBufAppendBufPlain(Target, 
00583                                         CCC->RecvBuf.ReadWritePointer, 
00584                                         RemainLen, 0);
00585                      CCC->RecvBuf.ReadWritePointer += RemainLen;
00586               }
00587               if ((ChrPtr(CCC->RecvBuf.Buf) + StrLength(CCC->RecvBuf.Buf)) <= CCC->RecvBuf.ReadWritePointer)
00588               {
00589                      CCC->RecvBuf.ReadWritePointer = NULL;
00590                      FlushStrBuf(CCC->RecvBuf.Buf);
00591               }
00592        }
00593 
00594        if (StrLength(Target) >= bytes + baselen)
00595               return 1;
00596 
00597        CCC->RecvBuf.ReadWritePointer = NULL;
00598 
00599        while ((StrLength(Target) < bytes + baselen) &&
00600               (retval >= 0))
00601        {
00602               retval = client_read_sslbuffer(CCC->RecvBuf.Buf, timeout);
00603               if (retval >= 0) {
00604                      RemainRead = bytes - (StrLength (Target) - baselen);
00605                      if (RemainRead < StrLength(CCC->RecvBuf.Buf))
00606                      {
00607                             StrBufAppendBufPlain(
00608                                    Target, 
00609                                    ChrPtr(CCC->RecvBuf.Buf), 
00610                                    RemainRead, 0);
00611                             CCC->RecvBuf.ReadWritePointer = ChrPtr(CCC->RecvBuf.Buf) + RemainRead;
00612                             break;
00613                      }
00614                      StrBufAppendBuf(Target, CCC->RecvBuf.Buf, 0); /* todo: Buf > bytes? */
00615                      FlushStrBuf(CCC->RecvBuf.Buf);
00616               }
00617               else 
00618               {
00619                      FlushStrBuf(CCC->RecvBuf.Buf);
00620                      return -1;
00621        
00622               }
00623        }
00624        return 1;
00625 }
00626 
00627 
00628 /*
00629  * CtdlStartTLS() starts SSL/TLS encryption for the current session.  It
00630  * must be supplied with pre-generated strings for responses of "ok," "no
00631  * support for TLS," and "error" so that we can use this in any protocol.
00632  */
00633 void CtdlStartTLS(char *ok_response, char *nosup_response,
00634                      char *error_response) {
00635 
00636        int retval, bits, alg_bits;
00637 
00638        if (!ssl_ctx) {
00639               syslog(LOG_CRIT, "SSL failed: no ssl_ctx exists?\n");
00640               if (nosup_response != NULL) cprintf("%s", nosup_response);
00641               return;
00642        }
00643        if (!(CC->ssl = SSL_new(ssl_ctx))) {
00644               syslog(LOG_CRIT, "SSL_new failed: %s\n",
00645                             ERR_reason_error_string(ERR_get_error()));
00646               if (error_response != NULL) cprintf("%s", error_response);
00647               return;
00648        }
00649        if (!(SSL_set_fd(CC->ssl, CC->client_socket))) {
00650               syslog(LOG_CRIT, "SSL_set_fd failed: %s\n",
00651                      ERR_reason_error_string(ERR_get_error()));
00652               SSL_free(CC->ssl);
00653               CC->ssl = NULL;
00654               if (error_response != NULL) cprintf("%s", error_response);
00655               return;
00656        }
00657        if (ok_response != NULL) cprintf("%s", ok_response);
00658        retval = SSL_accept(CC->ssl);
00659        if (retval < 1) {
00660               /*
00661                * Can't notify the client of an error here; they will
00662                * discover the problem at the SSL layer and should
00663                * revert to unencrypted communications.
00664                */
00665               long errval;
00666               char error_string[128];
00667 
00668               errval = SSL_get_error(CC->ssl, retval);
00669               syslog(LOG_CRIT, "SSL_accept failed: retval=%d, errval=%ld, err=%s\n",
00670                      retval,
00671                      errval,
00672                      ERR_error_string(errval, error_string)
00673               );
00674               SSL_free(CC->ssl);
00675               CC->ssl = NULL;
00676               return;
00677        }
00678        BIO_set_close(CC->ssl->rbio, BIO_NOCLOSE);
00679        bits = SSL_CIPHER_get_bits(SSL_get_current_cipher(CC->ssl), &alg_bits);
00680        syslog(LOG_INFO, "SSL/TLS using %s on %s (%d of %d bits)\n",
00681               SSL_CIPHER_get_name(SSL_get_current_cipher(CC->ssl)),
00682               SSL_CIPHER_get_version(SSL_get_current_cipher(CC->ssl)),
00683               bits, alg_bits);
00684        CC->redirect_ssl = 1;
00685 }
00686 
00687 
00688 /*
00689  * cmd_stls() starts SSL/TLS encryption for the current session
00690  */
00691 void cmd_stls(char *params)
00692 {
00693        char ok_response[SIZ];
00694        char nosup_response[SIZ];
00695        char error_response[SIZ];
00696 
00697        unbuffer_output();
00698 
00699        sprintf(ok_response,
00700               "%d Begin TLS negotiation now\n",
00701               CIT_OK);
00702        sprintf(nosup_response,
00703               "%d TLS not supported here\n",
00704               ERROR + CMD_NOT_SUPPORTED);
00705        sprintf(error_response,
00706               "%d TLS negotiation error\n",
00707               ERROR + INTERNAL_ERROR);
00708 
00709        CtdlStartTLS(ok_response, nosup_response, error_response);
00710 }
00711 
00712 
00713 /*
00714  * cmd_gtls() returns status info about the TLS connection
00715  */
00716 void cmd_gtls(char *params)
00717 {
00718        int bits, alg_bits;
00719 
00720        if (!CC->ssl || !CC->redirect_ssl) {
00721               cprintf("%d Session is not encrypted.\n", ERROR);
00722               return;
00723        }
00724        bits =
00725            SSL_CIPHER_get_bits(SSL_get_current_cipher(CC->ssl),
00726                             &alg_bits);
00727        cprintf("%d %s|%s|%d|%d\n", CIT_OK,
00728               SSL_CIPHER_get_version(SSL_get_current_cipher(CC->ssl)),
00729               SSL_CIPHER_get_name(SSL_get_current_cipher(CC->ssl)),
00730               alg_bits, bits);
00731 }
00732 
00733 
00734 /*
00735  * endtls() shuts down the TLS connection
00736  *
00737  * WARNING:  This may make your session vulnerable to a known plaintext
00738  * attack in the current implmentation.
00739  */
00740 void endtls(void)
00741 {
00742        if (!CC->ssl) {
00743               CC->redirect_ssl = 0;
00744               return;
00745        }
00746 
00747        syslog(LOG_INFO, "Ending SSL/TLS\n");
00748        SSL_shutdown(CC->ssl);
00749        SSL_free(CC->ssl);
00750        CC->ssl = NULL;
00751        CC->redirect_ssl = 0;
00752 }
00753 
00754 
00755 /*
00756  * ssl_lock() callback for OpenSSL mutex locks
00757  */
00758 void ssl_lock(int mode, int n, const char *file, int line)
00759 {
00760        if (mode & CRYPTO_LOCK)
00761               pthread_mutex_lock(SSLCritters[n]);
00762        else
00763               pthread_mutex_unlock(SSLCritters[n]);
00764 }
00765 #endif                      /* HAVE_OPENSSL */