• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

SSLUtils.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   @section license License
00004 
00005   Licensed to the Apache Software Foundation (ASF) under one
00006   or more contributor license agreements.  See the NOTICE file
00007   distributed with this work for additional information
00008   regarding copyright ownership.  The ASF licenses this file
00009   to you under the Apache License, Version 2.0 (the
00010   "License"); you may not use this file except in compliance
00011   with the License.  You may obtain a copy of the License at
00012 
00013       http://www.apache.org/licenses/LICENSE-2.0
00014 
00015   Unless required by applicable law or agreed to in writing, software
00016   distributed under the License is distributed on an "AS IS" BASIS,
00017   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00018   See the License for the specific language governing permissions and
00019   limitations under the License.
00020  */
00021 
00022 #include "ink_config.h"
00023 #include "libts.h"
00024 #include "I_Layout.h"
00025 #include "P_Net.h"
00026 #include "ink_cap.h"
00027 #include "P_OCSPStapling.h"
00028 
00029 #include <string>
00030 #include <openssl/err.h>
00031 #include <openssl/bio.h>
00032 #include <openssl/pem.h>
00033 #include <openssl/x509.h>
00034 #include <openssl/asn1.h>
00035 #include <openssl/rand.h>
00036 #include <unistd.h>
00037 #include <termios.h>
00038 
00039 #if HAVE_OPENSSL_EVP_H
00040 #include <openssl/evp.h>
00041 #endif
00042 
00043 #if HAVE_OPENSSL_HMAC_H
00044 #include <openssl/hmac.h>
00045 #endif
00046 
00047 #if HAVE_OPENSSL_TS_H
00048 #include <openssl/ts.h>
00049 #endif
00050 
00051 #if HAVE_OPENSSL_EC_H
00052 #include <openssl/ec.h>
00053 #endif
00054 
00055 // ssl_multicert.config field names:
00056 #define SSL_IP_TAG            "dest_ip"
00057 #define SSL_CERT_TAG          "ssl_cert_name"
00058 #define SSL_PRIVATE_KEY_TAG   "ssl_key_name"
00059 #define SSL_CA_TAG            "ssl_ca_name"
00060 #define SSL_SESSION_TICKET_ENABLED "ssl_ticket_enabled"
00061 #define SSL_SESSION_TICKET_KEY_FILE_TAG "ticket_key_name"
00062 #define SSL_KEY_DIALOG        "ssl_key_dialog"
00063 #define SSL_CERT_SEPARATE_DELIM ','
00064 
00065 // openssl version must be 0.9.4 or greater
00066 #if (OPENSSL_VERSION_NUMBER < 0x00090400L)
00067 # error Traffic Server requires an OpenSSL library version 0.9.4 or greater
00068 #endif
00069 
00070 #ifndef evp_md_func
00071 #ifdef OPENSSL_NO_SHA256
00072 #define evp_md_func EVP_sha1()
00073 #else
00074 #define evp_md_func EVP_sha256()
00075 #endif
00076 #endif
00077 
00078 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) // openssl returns a const SSL_METHOD
00079 typedef const SSL_METHOD * ink_ssl_method_t;
00080 #else
00081 typedef SSL_METHOD * ink_ssl_method_t;
00082 #endif
00083 
00084 // gather user provided settings from ssl_multicert.config in to a single struct
00085 struct ssl_user_config
00086 {
00087   ssl_user_config () : session_ticket_enabled(1) {
00088   }
00089 
00090   int session_ticket_enabled;  // ssl_ticket_enabled - session ticket enabled
00091   ats_scoped_str addr;   // dest_ip - IPv[64] address to match
00092   ats_scoped_str cert;   // ssl_cert_name - certificate
00093   ats_scoped_str first_cert; // the first certificate name when multiple cert files are in 'ssl_cert_name'
00094   ats_scoped_str ca;     // ssl_ca_name - CA public certificate
00095   ats_scoped_str key;    // ssl_key_name - Private key
00096   ats_scoped_str ticket_key_filename; // ticket_key_name - session key file. [key_name (16Byte) + HMAC_secret (16Byte) + AES_key (16Byte)]
00097   ats_scoped_str dialog; // ssl_key_dialog - Private key dialog
00098 };
00099 
00100 // Check if the ticket_key callback #define is available, and if so, enable session tickets.
00101 #ifdef SSL_CTX_set_tlsext_ticket_key_cb
00102 
00103 #define HAVE_OPENSSL_SESSION_TICKETS 1
00104 
00105 static void session_ticket_free(void *, void *, CRYPTO_EX_DATA *, int, long, void *);
00106 static int ssl_callback_session_ticket(SSL *, unsigned char *, unsigned char *, EVP_CIPHER_CTX *, HMAC_CTX *, int);
00107 #endif /* SSL_CTX_set_tlsext_ticket_key_cb */
00108 
00109 struct ssl_ticket_key_t
00110 {
00111   unsigned char key_name[16];
00112   unsigned char hmac_secret[16];
00113   unsigned char aes_key[16];
00114 };
00115 
00116 static int ssl_session_ticket_index = -1;
00117 static pthread_mutex_t *mutex_buf = NULL;
00118 static bool open_ssl_initialized = false;
00119 
00120 RecRawStatBlock *ssl_rsb = NULL;
00121 static InkHashTable *ssl_cipher_name_table = NULL;
00122 
00123 /* Using pthread thread ID and mutex functions directly, instead of
00124  * ATS this_ethread / ProxyMutex, so that other linked libraries
00125  * may use pthreads and openssl without confusing us here. (TS-2271).
00126  */
00127 
00128 static unsigned long
00129 SSL_pthreads_thread_id()
00130 {
00131   return (unsigned long)pthread_self();
00132 }
00133 
00134 static void
00135 SSL_locking_callback(int mode, int type, const char * /* file ATS_UNUSED */, int /* line ATS_UNUSED */)
00136 {
00137   ink_assert(type < CRYPTO_num_locks());
00138 
00139   if (mode & CRYPTO_LOCK) {
00140     pthread_mutex_lock(&mutex_buf[type]);
00141   } else if (mode & CRYPTO_UNLOCK) {
00142     pthread_mutex_unlock(&mutex_buf[type]);
00143   } else {
00144     Debug("ssl", "invalid SSL locking mode 0x%x", mode);
00145     ink_assert(0);
00146   }
00147 }
00148 
00149 static bool
00150 SSL_CTX_add_extra_chain_cert_file(SSL_CTX * ctx, const char * chainfile)
00151 {
00152   X509 *cert;
00153   scoped_BIO bio(BIO_new_file(chainfile, "r"));
00154 
00155   for (;;) {
00156     cert = PEM_read_bio_X509_AUX(bio.get(), NULL, NULL, NULL);
00157 
00158     if (!cert) {
00159       // No more the certificates in this file.
00160       break;
00161     }
00162 
00163     // This transfers ownership of the cert (X509) to the SSL context, if successful.
00164     if (!SSL_CTX_add_extra_chain_cert(ctx, cert)) {
00165       X509_free(cert);
00166       return false;
00167     }
00168   }
00169 
00170   return true;
00171 }
00172 
00173 #if TS_USE_TLS_SNI
00174 
00175 static int
00176 ssl_servername_callback(SSL * ssl, int * ad, void * arg)
00177 {
00178   SSL_CTX *           ctx = NULL;
00179   SSLCertLookup *     lookup = (SSLCertLookup *) arg;
00180   const char *        servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
00181   SSLNetVConnection * netvc = (SSLNetVConnection *)SSL_get_app_data(ssl);
00182 
00183   Debug("ssl", "ssl_servername_callback ssl=%p ad=%d lookup=%p server=%s handshake_complete=%d", ssl, *ad, lookup, servername,
00184     netvc->getSSLHandShakeComplete());
00185 
00186   // catch the client renegotiation early on
00187   if (SSLConfigParams::ssl_allow_client_renegotiation == false && netvc->getSSLHandShakeComplete()) {
00188     Debug("ssl", "ssl_servername_callback trying to renegotiate from the client");
00189     return SSL_TLSEXT_ERR_ALERT_FATAL;
00190   }
00191 
00192   // The incoming SSL_CTX is either the one mapped from the inbound IP address or the default one. If we
00193   // don't find a name-based match at this point, we *do not* want to mess with the context because we've
00194   // already made a best effort to find the best match.
00195   if (likely(servername)) {
00196     ctx = lookup->findInfoInHash((char *)servername);
00197   }
00198 
00199   // If there's no match on the server name, try to match on the peer address.
00200   if (ctx == NULL) {
00201     IpEndpoint ip;
00202     int namelen = sizeof(ip);
00203 
00204     safe_getsockname(netvc->get_socket(), &ip.sa, &namelen);
00205     ctx = lookup->findInfoInHash(ip);
00206   }
00207 
00208   if (ctx != NULL) {
00209     SSL_set_SSL_CTX(ssl, ctx);
00210   }
00211 
00212   ctx = SSL_get_SSL_CTX(ssl);
00213   Debug("ssl", "ssl_servername_callback found SSL context %p for requested name '%s'", ctx, servername);
00214 
00215   if (ctx == NULL) {
00216     return SSL_TLSEXT_ERR_NOACK;
00217   }
00218 
00219   // We need to return one of the SSL_TLSEXT_ERR constants. If we return an
00220   // error, we can fill in *ad with an alert code to propgate to the
00221   // client, see SSL_AD_*.
00222   return SSL_TLSEXT_ERR_OK;
00223 }
00224 
00225 #endif /* TS_USE_TLS_SNI */
00226 
00227 static SSL_CTX *
00228 ssl_context_enable_sni(SSL_CTX * ctx, SSLCertLookup * lookup)
00229 {
00230 #if TS_USE_TLS_SNI
00231   if (ctx) {
00232     Debug("ssl", "setting SNI callbacks with for ctx %p", ctx);
00233     SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_callback);
00234     SSL_CTX_set_tlsext_servername_arg(ctx, lookup);
00235   }
00236 #else
00237   (void)lookup;
00238 #endif /* TS_USE_TLS_SNI */
00239 
00240   return ctx;
00241 }
00242 
00243 static SSL_CTX *
00244 ssl_context_enable_ecdh(SSL_CTX * ctx)
00245 {
00246 #if TS_USE_TLS_ECKEY
00247 
00248 #if defined(SSL_CTRL_SET_ECDH_AUTO)
00249   SSL_CTX_set_ecdh_auto(ctx, 1);
00250 #elif defined(HAVE_EC_KEY_NEW_BY_CURVE_NAME) && defined(NID_X9_62_prime256v1)
00251   EC_KEY * ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
00252 
00253   if (ecdh) {
00254     SSL_CTX_set_tmp_ecdh(ctx, ecdh);
00255     EC_KEY_free(ecdh);
00256   }
00257 #endif
00258 #endif
00259 
00260   return ctx;
00261 }
00262 
00263 static SSL_CTX *
00264 ssl_context_enable_tickets(SSL_CTX * ctx, const char * ticket_key_path)
00265 {
00266 #if HAVE_OPENSSL_SESSION_TICKETS
00267   ats_scoped_str          ticket_key_data;
00268   int                 ticket_key_len;
00269   ssl_ticket_key_t *  ticket_key = NULL;
00270 
00271   ticket_key_data = readIntoBuffer(ticket_key_path, __func__, &ticket_key_len);
00272   if (!ticket_key_data) {
00273     Error("failed to read SSL session ticket key from %s", (const char *)ticket_key_path);
00274     goto fail;
00275   }
00276 
00277   if (ticket_key_len < 48) {
00278     Error("SSL session ticket key from %s is too short (48 bytes are required)", (const char *)ticket_key_path);
00279     goto fail;
00280   }
00281 
00282   ticket_key = new ssl_ticket_key_t();
00283   memcpy(ticket_key->key_name, (const char *)ticket_key_data, 16);
00284   memcpy(ticket_key->hmac_secret, (const char *)ticket_key_data + 16, 16);
00285   memcpy(ticket_key->aes_key, (const char *)ticket_key_data + 32, 16);
00286 
00287   // Setting the callback can only fail if OpenSSL does not recognize the
00288   // SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB constant. we set the callback first
00289   // so that we don't leave a ticket_key pointer attached if it fails.
00290   if (SSL_CTX_set_tlsext_ticket_key_cb(ctx, ssl_callback_session_ticket) == 0) {
00291     Error("failed to set session ticket callback");
00292     goto fail;
00293   }
00294 
00295   if (SSL_CTX_set_ex_data(ctx, ssl_session_ticket_index, ticket_key) == 0) {
00296     Error ("failed to set session ticket data to ctx");
00297     goto fail;
00298   }
00299 
00300   SSL_CTX_clear_options(ctx, SSL_OP_NO_TICKET);
00301   return ctx;
00302 
00303 fail:
00304   delete ticket_key;
00305   return ctx;
00306 
00307 #else /* !HAVE_OPENSSL_SESSION_TICKETS */
00308   (void)ticket_key_path;
00309   return ctx;
00310 #endif /* HAVE_OPENSSL_SESSION_TICKETS */
00311 }
00312 
00313 struct passphrase_cb_userdata
00314 {
00315     const SSLConfigParams * _configParams;
00316     const char * _serverDialog;
00317     const char * _serverCert;
00318     const char * _serverKey;
00319 
00320     passphrase_cb_userdata(const SSLConfigParams *params,const char *dialog, const char *cert, const char *key) :
00321             _configParams(params), _serverDialog(dialog), _serverCert(cert), _serverKey(key) {}
00322 };
00323 
00324 // RAII implementation for struct termios
00325 struct ssl_termios : public  termios
00326 {
00327   ssl_termios(int fd) {
00328     _fd = -1;
00329     // populate base class data
00330     if (tcgetattr(fd, this) == 0) { // success
00331        _fd = fd;
00332     }
00333     // save our copy
00334     _initialAttr = *this;
00335   }
00336 
00337   ~ssl_termios() {
00338     if (_fd != -1) {
00339       tcsetattr(_fd, 0, &_initialAttr);
00340     }
00341   }
00342 
00343   bool ok() {
00344     return (_fd != -1);
00345   }
00346 
00347 private:
00348   int _fd;
00349   struct termios _initialAttr;
00350 };
00351 
00352 static int
00353 ssl_getpassword(const char* prompt, char* buffer, int size)
00354 {
00355   fprintf(stdout, "%s", prompt);
00356 
00357   // disable echo and line buffering
00358   ssl_termios tty_attr(STDIN_FILENO);
00359 
00360   if (!tty_attr.ok()) {
00361     return -1;
00362   }
00363 
00364   tty_attr.c_lflag &= ~ICANON; // no buffer, no backspace
00365   tty_attr.c_lflag &= ~ECHO; // no echo
00366   tty_attr.c_lflag &= ~ISIG; // no signal for ctrl-c
00367 
00368   if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0) {
00369     return -1;
00370   }
00371 
00372   int i = 0;
00373   int ch = 0;
00374   *buffer = 0;
00375   while ((ch = getchar()) != '\n' && ch != EOF) {
00376     // make sure room in buffer
00377     if (i >= size - 1) {
00378       return -1;
00379     }
00380 
00381     buffer[i] = ch;
00382     buffer[++i] = 0;
00383   }
00384 
00385   return i;
00386 }
00387 
00388 static int
00389 ssl_private_key_passphrase_callback_exec(char *buf, int size, int rwflag, void *userdata)
00390 {
00391   if (0 == size) {
00392     return 0;
00393   }
00394 
00395   *buf = 0;
00396   passphrase_cb_userdata *ud = static_cast<passphrase_cb_userdata *> (userdata);
00397 
00398   Debug("ssl", "ssl_private_key_passphrase_callback_exec rwflag=%d serverDialog=%s", rwflag, ud->_serverDialog);
00399 
00400   // only respond to reading private keys, not writing them (does ats even do that?)
00401   if (0 == rwflag) {
00402     // execute the dialog program and use the first line output as the passphrase
00403     FILE *f = popen(ud->_serverDialog, "r");
00404     if (f) {
00405       if (fgets(buf, size, f)) {
00406         // remove any ending CR or LF
00407         for (char *pass = buf; *pass; pass++) {
00408           if (*pass == '\n' || *pass == '\r') {
00409             *pass = 0;
00410             break;
00411           }
00412         }
00413       }
00414       pclose(f);
00415     } else {// popen failed
00416       Error("could not open dialog '%s' - %s", ud->_serverDialog, strerror(errno));
00417     }
00418   }
00419   return strlen(buf);
00420 }
00421 
00422 static int
00423 ssl_private_key_passphrase_callback_builtin(char *buf, int size, int rwflag, void *userdata)
00424 {
00425   if (0 == size) {
00426     return 0;
00427   }
00428 
00429   *buf = 0;
00430   passphrase_cb_userdata *ud = static_cast<passphrase_cb_userdata *> (userdata);
00431 
00432   Debug("ssl", "ssl_private_key_passphrase_callback rwflag=%d serverDialog=%s", rwflag, ud->_serverDialog);
00433 
00434   // only respond to reading private keys, not writing them (does ats even do that?)
00435   if (0 == rwflag) {
00436     // output request
00437     fprintf(stdout, "Some of your private key files are encrypted for security reasons.\n");
00438     fprintf(stdout, "In order to read them you have to provide the pass phrases.\n");
00439     fprintf(stdout, "ssl_cert_name=%s", ud->_serverCert);
00440     if (ud->_serverKey) { // output ssl_key_name if provided
00441       fprintf(stdout, " ssl_key_name=%s", ud->_serverKey);
00442     }
00443     fprintf(stdout, "\n");
00444     // get passphrase
00445     // if error, then no passphrase
00446     if (ssl_getpassword("Enter passphrase:", buf, size) <= 0) {
00447       *buf = 0;
00448     }
00449     fprintf(stdout, "\n");
00450   }
00451   return strlen(buf);
00452 }
00453 
00454 static bool
00455 ssl_private_key_validate_exec(const char *cmdLine)
00456 {
00457   if (NULL == cmdLine) {
00458     errno = EINVAL;
00459     return false;
00460   }
00461 
00462   bool bReturn = false;
00463   char *cmdLineCopy = ats_strdup(cmdLine);
00464   char *ptr = cmdLineCopy;
00465 
00466   while(*ptr && !isspace(*ptr)) ++ptr;
00467   *ptr = 0;
00468   if (access(cmdLineCopy, X_OK) != -1) {
00469     bReturn = true;
00470   }
00471   ats_free(cmdLineCopy);
00472   return bReturn;
00473 }
00474 
00475 static int
00476 SSLRecRawStatSyncCount(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id)
00477 {
00478   // Grab all the stats we want from OpenSSL and set the stats. This function only needs to be called by one of the
00479   // involved stats, all others *must* call RecRawStatSyncSum.
00480   SSLCertificateConfig::scoped_config certLookup;
00481 
00482   int64_t sessions = 0;
00483   int64_t hits = 0;
00484   int64_t misses = 0;
00485   int64_t timeouts = 0;
00486 
00487   if (certLookup) {
00488     const unsigned ctxCount = certLookup->count();
00489     for (size_t i = 0; i < ctxCount; i++) {
00490       SSL_CTX * ctx = certLookup->get(i);
00491 
00492       sessions += SSL_CTX_sess_accept_good(ctx);
00493       hits += SSL_CTX_sess_hits(ctx);
00494       misses += SSL_CTX_sess_misses(ctx);
00495       timeouts += SSL_CTX_sess_timeouts(ctx);
00496     }
00497   }
00498 
00499   SSL_SET_COUNT_DYN_STAT(ssl_user_agent_sessions_stat, sessions);
00500   SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_hit_stat, hits);
00501   SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_miss_stat, misses);
00502   SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_timeout_stat, timeouts);
00503   return RecRawStatSyncCount(name, data_type, data, rsb, id);
00504 }
00505 
00506 void
00507 SSLInitializeLibrary()
00508 {
00509   if (!open_ssl_initialized) {
00510     CRYPTO_set_mem_functions(ats_malloc, ats_realloc, ats_free);
00511 
00512     SSL_load_error_strings();
00513     SSL_library_init();
00514 
00515     mutex_buf = (pthread_mutex_t *) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
00516 
00517     for (int i = 0; i < CRYPTO_num_locks(); i++) {
00518       pthread_mutex_init(&mutex_buf[i], NULL);
00519     }
00520 
00521     CRYPTO_set_locking_callback(SSL_locking_callback);
00522     CRYPTO_set_id_callback(SSL_pthreads_thread_id);
00523   }
00524 
00525 #ifdef SSL_CTX_set_tlsext_ticket_key_cb
00526   ssl_session_ticket_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, session_ticket_free);
00527   if (ssl_session_ticket_index == -1) {
00528     SSLError("failed to create session ticket index");
00529   }
00530 #endif
00531 
00532 #ifdef HAVE_OPENSSL_OCSP_STAPLING
00533   ssl_stapling_ex_init();
00534 #endif /* HAVE_OPENSSL_OCSP_STAPLING */
00535 
00536   open_ssl_initialized = true;
00537 }
00538 
00539 void
00540 SSLInitializeStatistics()
00541 {
00542   SSL_CTX *               ctx;
00543   SSL *                   ssl;
00544   STACK_OF(SSL_CIPHER) *  ciphers;
00545 
00546   // Allocate SSL statistics block.
00547   ssl_rsb = RecAllocateRawStatBlock((int) Ssl_Stat_Count);
00548   ink_assert(ssl_rsb != NULL);
00549 
00550   // SSL client errors.
00551   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_other_errors",
00552                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_other_errors_stat,
00553                      RecRawStatSyncSum);
00554   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_expired_cert",
00555                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_expired_cert_stat,
00556                      RecRawStatSyncSum);
00557   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_revoked_cert",
00558                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_revoked_cert_stat,
00559                      RecRawStatSyncSum);
00560   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_cert",
00561                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_unknown_cert_stat,
00562                      RecRawStatSyncSum);
00563   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_cert_verify_failed",
00564                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_cert_verify_failed_stat,
00565                      RecRawStatSyncSum);
00566   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_bad_cert",
00567                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_bad_cert_stat,
00568                      RecRawStatSyncSum);
00569   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_decryption_failed",
00570                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_decryption_failed_stat,
00571                      RecRawStatSyncSum);
00572   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_wrong_version",
00573                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_wrong_version_stat,
00574                      RecRawStatSyncSum);
00575   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_ca",
00576                      RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_unknown_ca_stat,
00577                      RecRawStatSyncSum);
00578 
00579   // Polled SSL context statistics.
00580   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_sessions",
00581                      RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_sessions_stat,
00582                      SSLRecRawStatSyncCount); //<- only use this fn once
00583   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_hit",
00584                      RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_session_hit_stat,
00585                      RecRawStatSyncCount);
00586   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_miss",
00587                      RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_session_miss_stat,
00588                      RecRawStatSyncCount);
00589   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_timeout",
00590                      RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_session_timeout_stat,
00591                      RecRawStatSyncCount);
00592 
00593   // SSL server errors.
00594   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_other_errors",
00595                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_other_errors_stat,
00596                      RecRawStatSyncSum);
00597   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_expired_cert",
00598                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_expired_cert_stat,
00599                      RecRawStatSyncSum);
00600   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_revoked_cert",
00601                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_revoked_cert_stat,
00602                      RecRawStatSyncSum);
00603   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_cert",
00604                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_unknown_cert_stat,
00605                      RecRawStatSyncSum);
00606   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_cert_verify_failed",
00607                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_cert_verify_failed_stat,
00608                      RecRawStatSyncSum);
00609   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_bad_cert",
00610                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_bad_cert_stat,
00611                      RecRawStatSyncSum);
00612   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_decryption_failed",
00613                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_decryption_failed_stat,
00614                      RecRawStatSyncSum);
00615   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_wrong_version",
00616                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_wrong_version_stat,
00617                      RecRawStatSyncSum);
00618   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_ca",
00619                      RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_unknown_ca_stat,
00620                      RecRawStatSyncSum);
00621 
00622   // SSL handshake time
00623   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_handshake_time",
00624                      RECD_INT, RECP_PERSISTENT, (int) ssl_total_handshake_time_stat,
00625                      RecRawStatSyncSum);
00626   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_success_handshake_count",
00627                      RECD_INT, RECP_PERSISTENT, (int) ssl_total_success_handshake_count_stat,
00628                      RecRawStatSyncCount);
00629 
00630   // TLS tickets
00631   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_created",
00632                      RECD_INT, RECP_PERSISTENT, (int) ssl_total_tickets_created_stat,
00633                      RecRawStatSyncCount);
00634   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_verified",
00635                      RECD_INT, RECP_PERSISTENT, (int) ssl_total_tickets_verified_stat,
00636                      RecRawStatSyncCount);
00637   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_not_found",
00638                      RECD_INT, RECP_PERSISTENT, (int) ssl_total_tickets_not_found_stat,
00639                      RecRawStatSyncCount);
00640   // TODO: ticket renewal is not used right now.
00641   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.total_tickets_renewed",
00642                      RECD_INT, RECP_PERSISTENT, (int) ssl_total_tickets_renewed_stat,
00643                      RecRawStatSyncCount);
00644 
00645 
00646   /* error stats */
00647   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_write",
00648                      RECD_INT, RECP_PERSISTENT, (int) ssl_error_want_write,
00649                      RecRawStatSyncCount);
00650   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_read",
00651                      RECD_INT, RECP_PERSISTENT, (int) ssl_error_want_read,
00652                      RecRawStatSyncCount);
00653   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_want_x509_lookup",
00654                      RECD_INT, RECP_PERSISTENT, (int) ssl_error_want_x509_lookup,
00655                      RecRawStatSyncCount);
00656   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_syscall",
00657                      RECD_INT, RECP_PERSISTENT, (int) ssl_error_syscall,
00658                      RecRawStatSyncCount);
00659   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_read_eos",
00660                      RECD_INT, RECP_PERSISTENT, (int) ssl_error_read_eos,
00661                      RecRawStatSyncCount);
00662   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_zero_return",
00663                      RECD_INT, RECP_PERSISTENT, (int) ssl_error_zero_return,
00664                      RecRawStatSyncCount);
00665   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_error_ssl",
00666                      RECD_INT, RECP_PERSISTENT, (int) ssl_error_ssl,
00667                      RecRawStatSyncCount);
00668   RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.ssl_sni_name_set_failure",
00669                        RECD_INT, RECP_PERSISTENT, (int) ssl_sni_name_set_failure,
00670                        RecRawStatSyncCount);
00671 
00672 
00673   // Get and register the SSL cipher stats. Note that we are using the default SSL context to obtain
00674   // the cipher list. This means that the set of ciphers is fixed by the build configuration and not
00675   // filtered by proxy.config.ssl.server.cipher_suite. This keeps the set of cipher suites stable across
00676   // configuration reloads and works for the case where we honor the client cipher preference.
00677 
00678   // initialize stat name->index hash table
00679   ssl_cipher_name_table = ink_hash_table_create(InkHashTableKeyType_Word);
00680 
00681   ctx = SSLDefaultServerContext();
00682   ssl = SSL_new(ctx);
00683   ciphers = SSL_get_ciphers(ssl);
00684 
00685   for (int index = 0; index < sk_SSL_CIPHER_num(ciphers); index++) {
00686     SSL_CIPHER * cipher = sk_SSL_CIPHER_value(ciphers, index);
00687     const char * cipherName = SSL_CIPHER_get_name(cipher);
00688     std::string  statName = "proxy.process.ssl.cipher.user_agent." + std::string(cipherName);
00689 
00690     // If room in allocated space ...
00691     if ((ssl_cipher_stats_start + index) > ssl_cipher_stats_end) {
00692       // Too many ciphers, increase ssl_cipher_stats_end.
00693       SSLError("too many ciphers to register metric '%s', increase SSL_Stats::ssl_cipher_stats_end",
00694                statName.c_str());
00695       continue;
00696     }
00697 
00698     // If not already registered ...
00699     if (!ink_hash_table_isbound(ssl_cipher_name_table, cipherName)) {
00700       ink_hash_table_insert(ssl_cipher_name_table, cipherName, (void *)(intptr_t) (ssl_cipher_stats_start + index));
00701       // Register as non-persistent since the order/index is dependent upon configuration.
00702       RecRegisterRawStat(ssl_rsb, RECT_PROCESS, statName.c_str(),
00703                          RECD_INT, RECP_NON_PERSISTENT, (int) ssl_cipher_stats_start + index,
00704                          RecRawStatSyncSum);
00705       SSL_CLEAR_DYN_STAT((int) ssl_cipher_stats_start + index);
00706       Debug("ssl", "registering SSL cipher metric '%s'", statName.c_str());
00707     }
00708   }
00709 
00710   SSL_free(ssl);
00711   SSL_CTX_free(ctx);
00712 }
00713 
00714 // return true if we have a stat for the error
00715 static bool
00716 increment_ssl_client_error(unsigned long err)
00717 {
00718   // we only look for LIB_SSL errors atm
00719   if (ERR_LIB_SSL != ERR_GET_LIB(err)) {
00720     SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat);
00721     return false;
00722   }
00723 
00724   // error was in LIB_SSL, now just switch on REASON
00725   // (we ignore FUNCTION with the prejudice that we don't care what function
00726   // the error came from, hope that's ok?)
00727   switch (ERR_GET_REASON(err)) {
00728   case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
00729     SSL_INCREMENT_DYN_STAT(ssl_user_agent_expired_cert_stat);
00730     break;
00731   case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
00732     SSL_INCREMENT_DYN_STAT(ssl_user_agent_revoked_cert_stat);
00733     break;
00734   case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
00735     SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_cert_stat);
00736     break;
00737   case SSL_R_CERTIFICATE_VERIFY_FAILED:
00738     SSL_INCREMENT_DYN_STAT(ssl_user_agent_cert_verify_failed_stat);
00739     break;
00740   case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
00741     SSL_INCREMENT_DYN_STAT(ssl_user_agent_bad_cert_stat);
00742     break;
00743   case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED:
00744     SSL_INCREMENT_DYN_STAT(ssl_user_agent_decryption_failed_stat);
00745     break;
00746   case SSL_R_WRONG_VERSION_NUMBER:
00747     SSL_INCREMENT_DYN_STAT(ssl_user_agent_wrong_version_stat);
00748     break;
00749   case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
00750     SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_ca_stat);
00751     break;
00752   default:
00753     SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat);
00754     return false;
00755   }
00756 
00757   return true;
00758 }
00759 
00760 // return true if we have a stat for the error
00761 
00762 static bool
00763 increment_ssl_server_error(unsigned long err)
00764 {
00765   // we only look for LIB_SSL errors atm
00766   if (ERR_LIB_SSL != ERR_GET_LIB(err)) {
00767     SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat);
00768     return false;
00769   }
00770 
00771   // error was in LIB_SSL, now just switch on REASON
00772   // (we ignore FUNCTION with the prejudice that we don't care what function
00773   // the error came from, hope that's ok?)
00774   switch (ERR_GET_REASON(err)) {
00775   case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
00776     SSL_INCREMENT_DYN_STAT(ssl_origin_server_expired_cert_stat);
00777     break;
00778   case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
00779     SSL_INCREMENT_DYN_STAT(ssl_origin_server_revoked_cert_stat);
00780     break;
00781   case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
00782     SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_cert_stat);
00783     break;
00784   case SSL_R_CERTIFICATE_VERIFY_FAILED:
00785     SSL_INCREMENT_DYN_STAT(ssl_origin_server_cert_verify_failed_stat);
00786     break;
00787   case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
00788     SSL_INCREMENT_DYN_STAT(ssl_origin_server_bad_cert_stat);
00789     break;
00790   case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED:
00791     SSL_INCREMENT_DYN_STAT(ssl_origin_server_decryption_failed_stat);
00792     break;
00793   case SSL_R_WRONG_VERSION_NUMBER:
00794     SSL_INCREMENT_DYN_STAT(ssl_origin_server_wrong_version_stat);
00795     break;
00796   case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
00797     SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_ca_stat);
00798     break;
00799   default:
00800     SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat);
00801     return false;
00802   }
00803 
00804   return true;
00805 }
00806 
00807 void
00808 SSLDiagnostic(const SrcLoc& loc, bool debug, SSLNetVConnection * vc, const char * fmt, ...)
00809 {
00810   unsigned long l;
00811   char buf[256];
00812   const char *file, *data;
00813   int line, flags;
00814   unsigned long es;
00815   va_list ap;
00816 
00817   ip_text_buffer ip_buf;
00818   bool ip_buf_flag = false;
00819   if (vc) {
00820     ats_ip_ntop(vc->get_remote_addr(), ip_buf, sizeof(ip_buf));
00821     ip_buf_flag = true;
00822   }
00823 
00824   es = CRYPTO_thread_id();
00825   while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
00826     if (debug) {
00827       if (unlikely(diags->on())) {
00828         diags->log("ssl", DL_Debug, loc.file, loc.func, loc.line,
00829             "SSL::%lu:%s:%s:%d%s%s%s%s", es, ERR_error_string(l, buf), file, line,
00830           (flags & ERR_TXT_STRING) ? ":" : "", (flags & ERR_TXT_STRING) ? data : "",
00831           ip_buf_flag? ": peer address is " : "", ip_buf);
00832       }
00833     } else {
00834       diags->error(DL_Error, loc.file, loc.func, loc.line,
00835           "SSL::%lu:%s:%s:%d%s%s%s%s", es, ERR_error_string(l, buf), file, line,
00836           (flags & ERR_TXT_STRING) ? ":" : "", (flags & ERR_TXT_STRING) ? data : "",
00837           ip_buf_flag? ": peer address is " : "", ip_buf);
00838     }
00839 
00840     // Tally desired stats (only client/server connection stats, not init
00841     // issues where vc is NULL)
00842     if (vc) {
00843       // getSSLClientConnection - true if ats is client (we update server stats)
00844       if (vc->getSSLClientConnection()) {
00845         increment_ssl_server_error(l); // update server error stats
00846       } else {
00847         increment_ssl_client_error(l); // update client error stat
00848       }
00849     }
00850   }
00851 
00852   va_start(ap, fmt);
00853   if (debug) {
00854     diags->log_va("ssl", DL_Debug, &loc, fmt, ap);
00855   } else {
00856     diags->error_va(DL_Error, loc.file, loc.func, loc.line, fmt, ap);
00857   }
00858   va_end(ap);
00859 
00860 }
00861 
00862 const char *
00863 SSLErrorName(int ssl_error)
00864 {
00865   static const char * names[] =  {
00866     "SSL_ERROR_NONE",
00867     "SSL_ERROR_SSL",
00868     "SSL_ERROR_WANT_READ",
00869     "SSL_ERROR_WANT_WRITE",
00870     "SSL_ERROR_WANT_X509_LOOKUP",
00871     "SSL_ERROR_SYSCALL",
00872     "SSL_ERROR_ZERO_RETURN",
00873     "SSL_ERROR_WANT_CONNECT",
00874     "SSL_ERROR_WANT_ACCEPT"
00875   };
00876 
00877   if (ssl_error < 0 || ssl_error >= (int)countof(names)) {
00878     return "unknown SSL error";
00879   }
00880 
00881   return names[ssl_error];
00882 }
00883 
00884 void
00885 SSLDebugBufferPrint(const char * tag, const char * buffer, unsigned buflen, const char * message)
00886 {
00887   if (is_debug_tag_set(tag)) {
00888     if (message != NULL) {
00889       fprintf(stdout, "%s\n", message);
00890     }
00891     for (unsigned ii = 0; ii < buflen; ii++) {
00892       putc(buffer[ii], stdout);
00893     }
00894     putc('\n', stdout);
00895   }
00896 }
00897 
00898 SSL_CTX *
00899 SSLDefaultServerContext()
00900 {
00901   ink_ssl_method_t meth = NULL;
00902 
00903   meth = SSLv23_server_method();
00904   return SSL_CTX_new(meth);
00905 }
00906 
00907 static bool
00908 SSLPrivateKeyHandler(
00909     SSL_CTX * ctx,
00910     const SSLConfigParams * params,
00911     const ats_scoped_str& completeServerCertPath,
00912     const char * keyPath)
00913 {
00914   if (!keyPath) {
00915     // assume private key is contained in cert obtained from multicert file.
00916     if (!SSL_CTX_use_PrivateKey_file(ctx, completeServerCertPath, SSL_FILETYPE_PEM)) {
00917       SSLError("failed to load server private key from %s", (const char *) completeServerCertPath);
00918       return false;
00919     }
00920   } else if (params->serverKeyPathOnly != NULL) {
00921     ats_scoped_str completeServerKeyPath(Layout::get()->relative_to(params->serverKeyPathOnly, keyPath));
00922     if (!SSL_CTX_use_PrivateKey_file(ctx, completeServerKeyPath, SSL_FILETYPE_PEM)) {
00923       SSLError("failed to load server private key from %s", (const char *) completeServerKeyPath);
00924       return false;
00925     }
00926   } else {
00927     SSLError("empty SSL private key path in records.config");
00928   }
00929 
00930   if (!SSL_CTX_check_private_key(ctx)) {
00931     SSLError("server private key does not match the certificate public key");
00932     return false;
00933   }
00934 
00935   return true;
00936 }
00937 
00938 SSL_CTX *
00939 SSLInitServerContext(
00940     const SSLConfigParams * params,
00941     const ssl_user_config & sslMultCertSettings)
00942 {
00943   int         session_id_context;
00944   int         server_verify_client;
00945   ats_scoped_str  completeServerCertPath;
00946   SSL_CTX *   ctx = SSLDefaultServerContext();
00947 
00948   // disable selected protocols
00949   SSL_CTX_set_options(ctx, params->ssl_ctx_options);
00950 
00951   switch (params->ssl_session_cache) {
00952   case SSLConfigParams::SSL_SESSION_CACHE_MODE_OFF:
00953     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_INTERNAL);
00954     break;
00955   case SSLConfigParams::SSL_SESSION_CACHE_MODE_SERVER:
00956     SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);
00957     SSL_CTX_sess_set_cache_size(ctx, params->ssl_session_cache_size);
00958     if (params->ssl_session_cache_timeout) {
00959         SSL_CTX_set_timeout(ctx, params->ssl_session_cache_timeout);
00960     }
00961     break;
00962   }
00963 
00964 #ifdef SSL_MODE_RELEASE_BUFFERS
00965   if (OPENSSL_VERSION_NUMBER > 0x1000107fL) {
00966     Debug("ssl", "enabling SSL_MODE_RELEASE_BUFFERS");
00967     SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
00968   }
00969 #endif
00970 
00971 #ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
00972   SSL_CTX_set_options(ctx, SSL_OP_SAFARI_ECDHE_ECDSA_BUG);
00973 #endif
00974 
00975   SSL_CTX_set_quiet_shutdown(ctx, 1);
00976 
00977   // pass phrase dialog configuration
00978   passphrase_cb_userdata ud(params, sslMultCertSettings.dialog, sslMultCertSettings.first_cert, sslMultCertSettings.key);
00979 
00980   if (sslMultCertSettings.dialog) {
00981     pem_password_cb * passwd_cb = NULL;
00982     if (strncmp(sslMultCertSettings.dialog, "exec:", 5) == 0) {
00983       ud._serverDialog = &sslMultCertSettings.dialog[5];
00984       // validate the exec program
00985       if (!ssl_private_key_validate_exec(ud._serverDialog)) {
00986         SSLError("failed to access '%s' pass phrase program: %s", (const char *) ud._serverDialog, strerror(errno));
00987         goto fail;
00988       }
00989       passwd_cb = ssl_private_key_passphrase_callback_exec;
00990     } else if (strcmp(sslMultCertSettings.dialog, "builtin") == 0) {
00991       passwd_cb = ssl_private_key_passphrase_callback_builtin;
00992     } else { // unknown config
00993       SSLError("unknown " SSL_KEY_DIALOG " configuration value '%s'", (const char *)sslMultCertSettings.dialog);
00994       goto fail;
00995     }
00996     SSL_CTX_set_default_passwd_cb(ctx, passwd_cb);
00997     SSL_CTX_set_default_passwd_cb_userdata(ctx, &ud);
00998   }
00999 
01000   if (!params->serverCertChainFilename && !sslMultCertSettings.ca && sslMultCertSettings.cert) {
01001     SimpleTokenizer cert_tok((const char *)sslMultCertSettings.cert, SSL_CERT_SEPARATE_DELIM);
01002     SimpleTokenizer key_tok((sslMultCertSettings.key ? (const char *)sslMultCertSettings.key : ""), SSL_CERT_SEPARATE_DELIM);
01003 
01004     if (sslMultCertSettings.key && cert_tok.getNumTokensRemaining() != key_tok.getNumTokensRemaining()) {
01005         Error("the number of certificates in ssl_cert_name and ssl_key_name doesn't match");
01006         goto fail;
01007     }
01008 
01009     for (const char * certname = cert_tok.getNext(); certname; certname = cert_tok.getNext()) {
01010       completeServerCertPath = Layout::relative_to(params->serverCertPathOnly, certname);
01011       if (SSL_CTX_use_certificate_chain_file(ctx, completeServerCertPath) < 0) {
01012         SSLError("failed to load certificate chain from %s", (const char *)completeServerCertPath);
01013         goto fail;
01014       }
01015 
01016       const char * keyPath = key_tok.getNext();
01017       if (!SSLPrivateKeyHandler(ctx, params, completeServerCertPath, keyPath)) {
01018         goto fail;
01019       }
01020     }
01021   } else if (sslMultCertSettings.first_cert) { // For backward compatible
01022       completeServerCertPath = Layout::relative_to(params->serverCertPathOnly, sslMultCertSettings.first_cert);
01023       if (!SSL_CTX_use_certificate_chain_file(ctx, completeServerCertPath)) {
01024           SSLError("failed to load certificate from %s", (const char *) completeServerCertPath);
01025           goto fail;
01026       }
01027 
01028     // First, load any CA chains from the global chain file.
01029     if (params->serverCertChainFilename) {
01030       ats_scoped_str completeServerCertChainPath(Layout::relative_to(params->serverCertPathOnly, params->serverCertChainFilename));
01031       if (!SSL_CTX_add_extra_chain_cert_file(ctx, completeServerCertChainPath)) {
01032         SSLError("failed to load global certificate chain from %s", (const char *) completeServerCertChainPath);
01033         goto fail;
01034       }
01035     }
01036 
01037     // Now, load any additional certificate chains specified in this entry.
01038     if (sslMultCertSettings.ca) {
01039       ats_scoped_str completeServerCertChainPath(Layout::relative_to(params->serverCertPathOnly, sslMultCertSettings.ca));
01040       if (!SSL_CTX_add_extra_chain_cert_file(ctx, completeServerCertChainPath)) {
01041         SSLError("failed to load certificate chain from %s", (const char *) completeServerCertChainPath);
01042         goto fail;
01043       }
01044     }
01045 
01046     if (!SSLPrivateKeyHandler(ctx, params, completeServerCertPath, sslMultCertSettings.key)) {
01047       goto fail;
01048     }
01049   }
01050 
01051   // SSL_CTX_load_verify_locations() builds the cert chain from the
01052   // serverCACertFilename if that is not NULL.  Otherwise, it uses the hashed
01053   // symlinks in serverCACertPath.
01054   //
01055   // if ssl_ca_name is NOT configured for this cert in ssl_multicert.config
01056   //     AND
01057   // if proxy.config.ssl.CA.cert.filename and proxy.config.ssl.CA.cert.path
01058   //     are configured
01059   //   pass that file as the chain (include all certs in that file)
01060   // else if proxy.config.ssl.CA.cert.path is configured (and
01061   //       proxy.config.ssl.CA.cert.filename is NULL)
01062   //   use the hashed symlinks in that directory to build the chain
01063   if (!sslMultCertSettings.ca && params->serverCACertPath != NULL) {
01064     if ((!SSL_CTX_load_verify_locations(ctx, params->serverCACertFilename, params->serverCACertPath)) ||
01065         (!SSL_CTX_set_default_verify_paths(ctx))) {
01066       SSLError("invalid CA Certificate file or CA Certificate path");
01067       goto fail;
01068     }
01069   }
01070 
01071   if (params->clientCertLevel != 0) {
01072 
01073     if (params->serverCACertFilename != NULL && params->serverCACertPath != NULL) {
01074       if ((!SSL_CTX_load_verify_locations(ctx, params->serverCACertFilename, params->serverCACertPath)) ||
01075           (!SSL_CTX_set_default_verify_paths(ctx))) {
01076         SSLError("CA Certificate file or CA Certificate path invalid");
01077         goto fail;
01078       }
01079     }
01080 
01081     if (params->clientCertLevel == 2) {
01082       server_verify_client = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE;
01083     } else if (params->clientCertLevel == 1) {
01084       server_verify_client = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
01085     } else {
01086       // disable client cert support
01087       server_verify_client = SSL_VERIFY_NONE;
01088       Error("illegal client certification level %d in records.config", server_verify_client);
01089     }
01090 
01091     // XXX I really don't think that this is a good idea. We should be setting this a some finer granularity,
01092     // possibly per SSL CTX. httpd uses md5(host:port), which seems reasonable.
01093     session_id_context = 1;
01094     SSL_CTX_set_session_id_context(ctx, (const unsigned char *) &session_id_context, sizeof(session_id_context));
01095 
01096     SSL_CTX_set_verify(ctx, server_verify_client, NULL);
01097     SSL_CTX_set_verify_depth(ctx, params->verify_depth); // might want to make configurable at some point.
01098 
01099     SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(params->serverCACertFilename));
01100   }
01101 
01102   if (params->cipherSuite != NULL) {
01103     if (!SSL_CTX_set_cipher_list(ctx, params->cipherSuite)) {
01104       SSLError("invalid cipher suite in records.config");
01105       goto fail;
01106     }
01107   }
01108 #define SSL_CLEAR_PW_REFERENCES(UD,CTX) { \
01109   memset(static_cast<void *>(&UD),0,sizeof(UD));\
01110   SSL_CTX_set_default_passwd_cb(CTX, NULL);\
01111   SSL_CTX_set_default_passwd_cb_userdata(CTX, NULL);\
01112   }
01113   SSL_CLEAR_PW_REFERENCES(ud,ctx)
01114   return ssl_context_enable_ecdh(ctx);
01115 
01116 fail:
01117   SSL_CLEAR_PW_REFERENCES(ud,ctx)
01118   SSL_CTX_free(ctx);
01119 
01120   return NULL;
01121 }
01122 
01123 SSL_CTX *
01124 SSLInitClientContext(const SSLConfigParams * params)
01125 {
01126   ink_ssl_method_t meth = NULL;
01127   SSL_CTX * client_ctx = NULL;
01128   char * clientKeyPtr = NULL;
01129 
01130   // Note that we do not call RAND_seed() explicitly here, we depend on OpenSSL
01131   // to do the seeding of the PRNG for us. This is the case for all platforms that
01132   // has /dev/urandom for example.
01133 
01134   meth = SSLv23_client_method();
01135   client_ctx = SSL_CTX_new(meth);
01136 
01137   // disable selected protocols
01138   SSL_CTX_set_options(client_ctx, params->ssl_ctx_options);
01139   if (!client_ctx) {
01140     SSLError("cannot create new client context");
01141     return NULL;
01142   }
01143 
01144   if (params->ssl_client_ctx_protocols) {
01145     SSL_CTX_set_options(client_ctx, params->ssl_client_ctx_protocols);
01146   }
01147   if (params->client_cipherSuite != NULL) {
01148     if (!SSL_CTX_set_cipher_list(client_ctx, params->client_cipherSuite)) {
01149       SSLError("invalid client cipher suite in records.config");
01150       goto fail;
01151     }
01152   }
01153 
01154   // if no path is given for the client private key,
01155   // assume it is contained in the client certificate file.
01156   clientKeyPtr = params->clientKeyPath;
01157   if (clientKeyPtr == NULL) {
01158     clientKeyPtr = params->clientCertPath;
01159   }
01160 
01161   if (params->clientCertPath != 0) {
01162     if (!SSL_CTX_use_certificate_chain_file(client_ctx, params->clientCertPath)) {
01163       SSLError("failed to load client certificate from %s", params->clientCertPath);
01164       goto fail;
01165     }
01166 
01167     if (!SSL_CTX_use_PrivateKey_file(client_ctx, clientKeyPtr, SSL_FILETYPE_PEM)) {
01168       SSLError("failed to load client private key file from %s", clientKeyPtr);
01169       goto fail;
01170     }
01171 
01172     if (!SSL_CTX_check_private_key(client_ctx)) {
01173       SSLError("client private key (%s) does not match the certificate public key (%s)",
01174           clientKeyPtr, params->clientCertPath);
01175       goto fail;
01176     }
01177   }
01178 
01179   if (params->clientVerify) {
01180     int client_verify_server;
01181 
01182     client_verify_server = params->clientVerify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
01183     SSL_CTX_set_verify(client_ctx, client_verify_server, NULL);
01184     SSL_CTX_set_verify_depth(client_ctx, params->client_verify_depth);
01185 
01186     if (params->clientCACertFilename != NULL && params->clientCACertPath != NULL) {
01187       if (!SSL_CTX_load_verify_locations(client_ctx, params->clientCACertFilename, params->clientCACertPath)) {
01188         SSLError("invalid client CA Certificate file (%s) or CA Certificate path (%s)",
01189             params->clientCACertFilename, params->clientCACertPath);
01190         goto fail;
01191       }
01192     }
01193 
01194     if (!SSL_CTX_set_default_verify_paths(client_ctx)) {
01195       SSLError("failed to set the default verify paths");
01196       goto fail;
01197     }
01198   }
01199 
01200   if (SSLConfigParams::init_ssl_ctx_cb) {
01201     SSLConfigParams::init_ssl_ctx_cb(client_ctx, false);
01202   }
01203 
01204   return client_ctx;
01205 
01206 fail:
01207   SSL_CTX_free(client_ctx);
01208   return NULL;
01209 }
01210 
01211 static char *
01212 asn1_strdup(ASN1_STRING * s)
01213 {
01214   // Make sure we have an 8-bit encoding.
01215   ink_assert(ASN1_STRING_type(s) == V_ASN1_IA5STRING ||
01216     ASN1_STRING_type(s) == V_ASN1_UTF8STRING ||
01217     ASN1_STRING_type(s) == V_ASN1_PRINTABLESTRING ||
01218     ASN1_STRING_type(s) == V_ASN1_T61STRING);
01219 
01220   return ats_strndup((const char *)ASN1_STRING_data(s), ASN1_STRING_length(s));
01221 }
01222 
01223 // Given a certificate and it's corresponding SSL_CTX context, insert hash
01224 // table aliases for subject CN and subjectAltNames DNS without wildcard,
01225 // insert trie aliases for those with wildcard.
01226 static void
01227 ssl_index_certificate(SSLCertLookup * lookup, SSL_CTX * ctx, const char * certfile)
01228 {
01229   X509_NAME *   subject = NULL;
01230   X509 *        cert;
01231   scoped_BIO    bio(BIO_new_file(certfile, "r"));
01232 
01233   cert = PEM_read_bio_X509_AUX(bio.get(), NULL, NULL, NULL);
01234   if (NULL == cert) {
01235     return;
01236   }
01237 
01238   // Insert a key for the subject CN.
01239   subject = X509_get_subject_name(cert);
01240   if (subject) {
01241     int pos = -1;
01242     for (;;) {
01243       pos = X509_NAME_get_index_by_NID(subject, NID_commonName, pos);
01244       if (pos == -1) {
01245         break;
01246       }
01247 
01248       X509_NAME_ENTRY * e = X509_NAME_get_entry(subject, pos);
01249       ASN1_STRING * cn = X509_NAME_ENTRY_get_data(e);
01250       ats_scoped_str name(asn1_strdup(cn));
01251 
01252       Debug("ssl", "mapping '%s' to certificate %s", (const char *) name, certfile);
01253       lookup->insert(ctx, name);
01254     }
01255   }
01256 
01257 #if HAVE_OPENSSL_TS_H
01258   // Traverse the subjectAltNames (if any) and insert additional keys for the SSL context.
01259   GENERAL_NAMES * names = (GENERAL_NAMES *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
01260   if (names) {
01261     unsigned count = sk_GENERAL_NAME_num(names);
01262     for (unsigned i = 0; i < count; ++i) {
01263       GENERAL_NAME * name;
01264 
01265       name = sk_GENERAL_NAME_value(names, i);
01266       if (name->type == GEN_DNS) {
01267         ats_scoped_str dns(asn1_strdup(name->d.dNSName));
01268         Debug("ssl", "mapping '%s' to certificate %s", (const char *) dns, certfile);
01269         lookup->insert(ctx, dns);
01270       }
01271     }
01272 
01273     GENERAL_NAMES_free(names);
01274   }
01275 #endif // HAVE_OPENSSL_TS_H
01276   X509_free(cert);
01277 }
01278 
01279 // This callback function is executed while OpenSSL processes the SSL
01280 // handshake and does SSL record layer stuff.  It's used to trap
01281 // client-initiated renegotiations and update cipher stats
01282 static void
01283 ssl_callback_info(const SSL *ssl, int where, int ret)
01284 {
01285   Debug("ssl", "ssl_callback_info ssl: %p where: %d ret: %d", ssl, where, ret);
01286   SSLNetVConnection * netvc = (SSLNetVConnection *)SSL_get_app_data(ssl);
01287 
01288   if ((where & SSL_CB_ACCEPT_LOOP) && netvc->getSSLHandShakeComplete() == true &&
01289       SSLConfigParams::ssl_allow_client_renegotiation == false) {
01290     int state = SSL_get_state(ssl);
01291 
01292     if (state == SSL3_ST_SR_CLNT_HELLO_A || state == SSL23_ST_SR_CLNT_HELLO_A) {
01293       netvc->setSSLClientRenegotiationAbort(true);
01294       Debug("ssl", "ssl_callback_info trying to renegotiate from the client");
01295     }
01296   }
01297   if (where & SSL_CB_HANDSHAKE_DONE) {
01298     // handshake is complete
01299     const SSL_CIPHER * cipher = SSL_get_current_cipher(ssl);
01300     if (cipher) {
01301       const char * cipherName = SSL_CIPHER_get_name(cipher);
01302       // lookup index of stat by name and incr count
01303       InkHashTableValue data;
01304       if (ink_hash_table_lookup(ssl_cipher_name_table, cipherName, &data)) {
01305         SSL_INCREMENT_DYN_STAT((intptr_t)data);
01306       }
01307     }
01308   }
01309 }
01310 
01311 static bool
01312 ssl_store_ssl_context(
01313     const SSLConfigParams * params,
01314     SSLCertLookup *         lookup,
01315     const ssl_user_config & sslMultCertSettings)
01316 {
01317   SSL_CTX *   ctx;
01318   ats_scoped_str  certpath;
01319   ats_scoped_str  session_key_path;
01320 
01321   ctx = ssl_context_enable_sni(SSLInitServerContext(params, sslMultCertSettings), lookup);
01322   if (!ctx) {
01323     return false;
01324   }
01325 
01326   SSL_CTX_set_info_callback(ctx, ssl_callback_info);
01327 
01328 #if TS_USE_TLS_NPN
01329   SSL_CTX_set_next_protos_advertised_cb(ctx, SSLNetVConnection::advertise_next_protocol, NULL);
01330 #endif /* TS_USE_TLS_NPN */
01331 
01332 #if TS_USE_TLS_ALPN
01333   SSL_CTX_set_alpn_select_cb(ctx, SSLNetVConnection::select_next_protocol, NULL);
01334 #endif /* TS_USE_TLS_ALPN */
01335 
01336   certpath = Layout::relative_to(params->serverCertPathOnly, sslMultCertSettings.first_cert);
01337 
01338   // Index this certificate by the specified IP(v6) address. If the address is "*", make it the default context.
01339   if (sslMultCertSettings.addr) {
01340     if (strcmp(sslMultCertSettings.addr, "*") == 0) {
01341       lookup->ssl_default = ctx;
01342       lookup->insert(ctx, sslMultCertSettings.addr);
01343     } else {
01344       IpEndpoint ep;
01345 
01346       if (ats_ip_pton(sslMultCertSettings.addr, &ep) == 0) {
01347         Debug("ssl", "mapping '%s' to certificate %s", (const char *)sslMultCertSettings.addr, (const char *)certpath);
01348         lookup->insert(ctx, ep);
01349       } else {
01350         Error("'%s' is not a valid IPv4 or IPv6 address", (const char *)sslMultCertSettings.addr);
01351       }
01352     }
01353   }
01354 
01355 #if defined(SSL_OP_NO_TICKET)
01356   // Session tickets are enabled by default. Disable if explicitly requested.
01357   if (sslMultCertSettings.session_ticket_enabled == 0) {
01358     SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
01359     Debug("ssl", "ssl session ticket is disabled");
01360   }
01361 #endif
01362 
01363   // Load the session ticket key if session tickets are not disabled and we have key name.
01364   if (sslMultCertSettings.session_ticket_enabled != 0 && sslMultCertSettings.ticket_key_filename) {
01365     ats_scoped_str ticket_key_path(Layout::relative_to(params->serverCertPathOnly, sslMultCertSettings.ticket_key_filename));
01366     ssl_context_enable_tickets(ctx, ticket_key_path);
01367   }
01368 
01369 #ifdef HAVE_OPENSSL_OCSP_STAPLING
01370   if (SSLConfigParams::ssl_ocsp_enabled) {
01371     Debug("ssl", "ssl ocsp stapling is enabled");
01372     SSL_CTX_set_tlsext_status_cb(ctx, ssl_callback_ocsp_stapling);
01373     if (!ssl_stapling_init_cert(ctx, (const char *)certpath)) {
01374       Error("fail to configure SSL_CTX for OCSP Stapling info");
01375     }
01376   } else {
01377     Debug("ssl", "ssl ocsp stapling is disabled");
01378   }
01379 #else
01380   if (SSLConfigParams::ssl_ocsp_enabled) {
01381     Error("fail to enable ssl ocsp stapling, this openssl version does not support it");
01382   }
01383 #endif /* HAVE_OPENSSL_OCSP_STAPLING */
01384 
01385   // Insert additional mappings. Note that this maps multiple keys to the same value, so when
01386   // this code is updated to reconfigure the SSL certificates, it will need some sort of
01387   // refcounting or alternate way of avoiding double frees.
01388   Debug("ssl", "importing SNI names from %s", (const char *)certpath);
01389   ssl_index_certificate(lookup, ctx, certpath);
01390 
01391   if (SSLConfigParams::init_ssl_ctx_cb) {
01392     SSLConfigParams::init_ssl_ctx_cb(ctx, true);
01393   }
01394 
01395   return true;
01396 }
01397 
01398 static bool
01399 ssl_extract_certificate(
01400     const matcher_line * line_info,
01401     ssl_user_config & sslMultCertSettings)
01402 
01403 {
01404   for (int i = 0; i < MATCHER_MAX_TOKENS; ++i) {
01405     const char * label;
01406     const char * value;
01407 
01408     label = line_info->line[0][i];
01409     value = line_info->line[1][i];
01410 
01411     if (label == NULL) {
01412       continue;
01413     }
01414 
01415     if (strcasecmp(label, SSL_IP_TAG) == 0) {
01416       sslMultCertSettings.addr = ats_strdup(value);
01417     }
01418 
01419     if (strcasecmp(label, SSL_CERT_TAG) == 0) {
01420       sslMultCertSettings.cert = ats_strdup(value);
01421     }
01422 
01423     if (strcasecmp(label, SSL_CA_TAG) == 0) {
01424       sslMultCertSettings.ca = ats_strdup(value);
01425     }
01426 
01427     if (strcasecmp(label, SSL_PRIVATE_KEY_TAG) == 0) {
01428       sslMultCertSettings.key = ats_strdup(value);
01429     }
01430 
01431     if (strcasecmp(label, SSL_SESSION_TICKET_ENABLED) == 0) {
01432       sslMultCertSettings.session_ticket_enabled = atoi(value);
01433     }
01434 
01435     if (strcasecmp(label, SSL_SESSION_TICKET_KEY_FILE_TAG) == 0) {
01436       sslMultCertSettings.ticket_key_filename = ats_strdup(value);
01437     }
01438 
01439     if (strcasecmp(label, SSL_KEY_DIALOG) == 0) {
01440       sslMultCertSettings.dialog = ats_strdup(value);
01441     }
01442   }
01443   if (!sslMultCertSettings.cert) {
01444     Error("missing %s tag", SSL_CERT_TAG);
01445     return false;
01446   }
01447 
01448   SimpleTokenizer cert_tok(sslMultCertSettings.cert, SSL_CERT_SEPARATE_DELIM);
01449   const char * first_cert = cert_tok.getNext();
01450   if (first_cert) {
01451       sslMultCertSettings.first_cert = ats_strdup(first_cert);
01452   }
01453 
01454   return true;
01455 }
01456 
01457 bool
01458 SSLParseCertificateConfiguration(
01459     const SSLConfigParams * params,
01460     SSLCertLookup *         lookup)
01461 {
01462   char *      tok_state = NULL;
01463   char *      line = NULL;
01464   ats_scoped_str  file_buf;
01465   unsigned    line_num = 0;
01466   matcher_line line_info;
01467 
01468   const matcher_tags sslCertTags = {
01469     NULL, NULL, NULL, NULL, NULL, NULL, false
01470   };
01471 
01472   Note("loading SSL certificate configuration from %s", params->configFilePath);
01473 
01474   if (params->configFilePath) {
01475     file_buf = readIntoBuffer(params->configFilePath, __func__, NULL);
01476   }
01477 
01478   if (!file_buf) {
01479     Error("failed to read SSL certificate configuration from %s", params->configFilePath);
01480     return false;
01481   }
01482 
01483   // elevate/allow file access to root read only files/certs
01484   uint32_t elevate_setting = 0;
01485   REC_ReadConfigInteger(elevate_setting, "proxy.config.ssl.cert.load_elevated");
01486   ElevateAccess elevate_access(elevate_setting != 0); // destructor will demote for us
01487 
01488   line = tokLine(file_buf, &tok_state);
01489   while (line != NULL) {
01490 
01491     line_num++;
01492 
01493     // skip all blank spaces at beginning of line
01494     while (*line && isspace(*line)) {
01495       line++;
01496     }
01497 
01498     if (*line != '\0' && *line != '#') {
01499       ssl_user_config sslMultiCertSettings;
01500       const char * errPtr;
01501 
01502       errPtr = parseConfigLine(line, &line_info, &sslCertTags);
01503 
01504       if (errPtr != NULL) {
01505         RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s: discarding %s entry at line %d: %s",
01506                      __func__, params->configFilePath, line_num, errPtr);
01507       } else {
01508         if (ssl_extract_certificate(&line_info, sslMultiCertSettings)) {
01509           if (!ssl_store_ssl_context(params, lookup, sslMultiCertSettings)) {
01510             Error("failed to load SSL certificate specification from %s line %u",
01511                 params->configFilePath, line_num);
01512           }
01513         } else {
01514           RecSignalWarning(REC_SIGNAL_CONFIG_ERROR, "%s: discarding invalid %s entry at line %u",
01515                        __func__, params->configFilePath, line_num);
01516         }
01517       }
01518 
01519     }
01520 
01521     line = tokLine(NULL, &tok_state);
01522   }
01523 
01524   // We *must* have a default context even if it can't possibly work. The default context is used to
01525   // bootstrap the SSL handshake so that we can subsequently do the SNI lookup to switch to the real
01526   // context.
01527   if (lookup->ssl_default == NULL) {
01528     ssl_user_config sslMultiCertSettings;
01529     sslMultiCertSettings.addr = ats_strdup("*");
01530     ssl_store_ssl_context(params, lookup, sslMultiCertSettings);
01531   }
01532 
01533   return true;
01534 }
01535 
01536 #if HAVE_OPENSSL_SESSION_TICKETS
01537 
01538 static void
01539 session_ticket_free(void * /*parent*/, void * ptr, CRYPTO_EX_DATA * /*ad*/,
01540     int /*idx*/, long /*argl*/, void * /*argp*/)
01541 {
01542   ssl_ticket_key_t * key = (ssl_ticket_key_t *)ptr;
01543   delete key;
01544 }
01545 
01546 /*
01547  * RFC 5077. Create session ticket to resume SSL session without requiring session-specific state at the TLS server.
01548  * Specifically, it distributes the encrypted session-state information to the client in the form of a ticket and
01549  * a mechanism to present the ticket back to the server.
01550  * */
01551 static int
01552 ssl_callback_session_ticket(
01553     SSL * ssl,
01554     unsigned char * keyname,
01555     unsigned char * iv,
01556     EVP_CIPHER_CTX * cipher_ctx,
01557     HMAC_CTX * hctx,
01558     int enc)
01559 {
01560   ssl_ticket_key_t* ssl_ticket_key = (ssl_ticket_key_t*) SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl), ssl_session_ticket_index);
01561 
01562   if (NULL == ssl_ticket_key) {
01563     Error("ssl ticket key is null.");
01564     return -1;
01565   }
01566 
01567   if (enc == 1) {
01568     memcpy(keyname, ssl_ticket_key->key_name, 16);
01569     RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH);
01570     EVP_EncryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL, ssl_ticket_key->aes_key, iv);
01571     HMAC_Init_ex(hctx, ssl_ticket_key->hmac_secret, 16, evp_md_func, NULL);
01572 
01573     Debug("ssl", "create ticket for a new session.");
01574     SSL_INCREMENT_DYN_STAT(ssl_total_tickets_created_stat);
01575     return 0;
01576   } else if (enc == 0) {
01577     if (memcmp(keyname, ssl_ticket_key->key_name, 16)) {
01578       Debug("ssl", "keyname is not consistent.");
01579       SSL_INCREMENT_DYN_STAT(ssl_total_tickets_not_found_stat);
01580       return 0;
01581     }
01582 
01583     EVP_DecryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL, ssl_ticket_key->aes_key, iv);
01584     HMAC_Init_ex(hctx, ssl_ticket_key->hmac_secret, 16, evp_md_func, NULL);
01585 
01586     Debug("ssl", "verify the ticket for an existing session.");
01587     SSL_INCREMENT_DYN_STAT(ssl_total_tickets_verified_stat);
01588     return 1;
01589   }
01590 
01591   return -1;
01592 }
01593 #endif /* HAVE_OPENSSL_SESSION_TICKETS */
01594 
01595 void
01596 SSLReleaseContext(SSL_CTX * ctx)
01597 {
01598   SSL_CTX_free(ctx);
01599 }

Generated by  doxygen 1.7.1