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

Generated by  doxygen 1.7.1