Repository: trafficserver
Updated Branches:
  refs/heads/master 61e6dcd51 -> e0c35aa8a


TS-612: add support for SSL keys with passphrases

Add support for dialog settings in ssl_multicert.config to allow for
passphrase protected private keys.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/e0c35aa8
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/e0c35aa8
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/e0c35aa8

Branch: refs/heads/master
Commit: e0c35aa8aad57ae473d02528c67f96da5b549b8c
Parents: 61e6dcd
Author: Ron Barber <[email protected]>
Authored: Tue Feb 18 13:36:40 2014 -0600
Committer: James Peach <[email protected]>
Committed: Tue Feb 25 15:14:12 2014 -0800

----------------------------------------------------------------------
 CHANGES                                         |   3 +
 .../configuration/ssl_multicert.config.en.rst   |  30 +-
 iocore/net/P_SSLUtils.h                         |   8 -
 iocore/net/SSLUtils.cc                          | 294 ++++++++++++++++---
 proxy/config/ssl_multicert.config.default       |  11 +-
 5 files changed, 287 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e0c35aa8/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 3fc0e38..a4b08be 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 5.0.0
 
+  *) [TS-612] Add support for SSL keys with passphrases.
+   Author: Ron Barber <[email protected]>
+
   *) [TS-2319] Change default behavior for the various ignore-mismatch
    configurations.
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e0c35aa8/doc/reference/configuration/ssl_multicert.config.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/configuration/ssl_multicert.config.en.rst 
b/doc/reference/configuration/ssl_multicert.config.en.rst
index 331e47e..f3ff295 100644
--- a/doc/reference/configuration/ssl_multicert.config.en.rst
+++ b/doc/reference/configuration/ssl_multicert.config.en.rst
@@ -94,6 +94,22 @@ ticket_key_name=FILENAME
   specified, and internal session ticket key is generated. This
   key will be different each time Traffic Server is started.
 
+ssl_key_dialog=builtin|"exec:/path/to/program [args]"
+  Method used to provide a pass phrase for encrypted private keys.  If the
+  pass phrase is incorrect, SSL negotiation for this dest_ip will fail for
+  clients who attempt to connect.
+  Two options are supported: builtin and exec
+    ``builtin`` - Requests pass phrase via stdin/stdout. User will be
+      provided the ssl_cert_name and be prompted for the pass phrase.
+      Useful for debugging.
+    ``exec:`` - Executes program /path/to/program and passes args, if
+      specified, to the program and reads the output from stdout for
+      the pass phrase.  If args are provided then the entire exec: string
+      must be quoted with "" (see examples).  Arguments with white space
+      are supported by single quoting (').  The intent is that this
+      program runs a security check to ensure that the system is not
+      compromised by an attacker before providing the pass phrase.
+
 Certificate Selection
 =====================
 
@@ -153,9 +169,21 @@ key.
     dest_ip=111.11.11.1 ssl_cert_name=server.pem ssl_ticket_enabled=1 
ticket_key_name=ticket.key
 
 The following example configures Traffic Server to use the SSL
-certificate ``server.pem`` and disable sessiont ticket for all
+certificate ``server.pem`` and disable session tickets for all
 requests to the IP address 111.11.11.1.
 
 ::
 
     dest_ip=111.11.11.1 ssl_cert_name=server.pem ssl_ticket_enabled=0
+
+The following examples configure Traffic Server to use the SSL
+certificate ``server.pem`` which includes an encrypted private key.
+The external program /usr/bin/mypass will be called on startup with one
+parameter (foo) in the first example, and with two parameters (foo)
+and (ba r) in the second example, the program (mypass) will return the
+pass phrase to decrypt the keys.
+
+::
+
+    ssl_cert_name=server1.pem ssl_key_dialog="exec:/usr/bin/mypass foo"
+    ssl_cert_name=server2.pem ssl_key_dialog="exec:/usr/bin/mypass foo 'ba r'"

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e0c35aa8/iocore/net/P_SSLUtils.h
----------------------------------------------------------------------
diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h
index 5ed2d82..e517824 100644
--- a/iocore/net/P_SSLUtils.h
+++ b/iocore/net/P_SSLUtils.h
@@ -48,14 +48,6 @@ struct SSLCertLookup;
 // Create a default SSL server context.
 SSL_CTX * SSLDefaultServerContext();
 
-// Create and initialize a SSL server context.
-SSL_CTX *
-SSLInitServerContext(
-    const SSLConfigParams * param,
-    const char * serverCertPtr,
-    const char * serverCaCertPtr,
-    const char * serverKeyPtr);
-
 // Create and initialize a SSL client context.
 SSL_CTX * SSLInitClientContext(const SSLConfigParams * param);
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e0c35aa8/iocore/net/SSLUtils.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 6ec3208..d066416 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -31,6 +31,8 @@
 #include <openssl/x509.h>
 #include <openssl/asn1.h>
 #include <openssl/rand.h>
+#include <unistd.h>
+#include <termios.h>
 
 #if HAVE_OPENSSL_EVP_H
 #include <openssl/evp.h>
@@ -55,6 +57,12 @@
 #define SSL_CA_TAG            "ssl_ca_name"
 #define SSL_SESSION_TICKET_ENABLED "ssl_ticket_enabled"
 #define SSL_SESSION_TICKET_KEY_FILE_TAG "ticket_key_name"
+#define SSL_KEY_DIALOG        "ssl_key_dialog"
+
+// openssl version must be 0.9.4 or greater
+#if (OPENSSL_VERSION_NUMBER < 0x00090400L)
+# error Traffic Server requires an OpenSSL library version 0.9.4 or greater
+#endif
 
 #ifndef evp_md_func
 #ifdef OPENSSL_NO_SHA256
@@ -70,6 +78,18 @@ typedef const SSL_METHOD * ink_ssl_method_t;
 typedef SSL_METHOD * ink_ssl_method_t;
 #endif
 
+// gather user provided settings from ssl_multicert.config in to a single 
struct
+struct ssl_user_config
+{
+    xptr<char> addr;   // dest_ip - IPv[64] address to match
+    xptr<char> cert;   // ssl_cert_name - certificate
+    xptr<char> ca;     // ssl_ca_name - CA public certificate
+    xptr<char> key;    // ssl_key_name - Private key
+    int  session_ticket_enabled;  // ssl_ticket_enabled - session ticket 
enabled
+    xptr<char> ticket_key_filename; // ticket_key_name - session key file. 
[key_name (16Byte) + HMAC_secret (16Byte) + AES_key (16Byte)]
+    xptr<char> dialog; // ssl_key_dialog - Private key dialog
+};
+
 // Check if the ticket_key callback #define is available, and if so, enable 
session tickets.
 #ifdef SSL_CTX_set_tlsext_ticket_key_cb
 #  define HAVE_OPENSSL_SESSION_TICKETS 1
@@ -303,6 +323,168 @@ fail:
 #endif /* HAVE_OPENSSL_SESSION_TICKETS */
 }
 
+struct passphrase_cb_userdata
+{
+    const SSLConfigParams * _configParams;
+    const char * _serverDialog;
+    const char * _serverCert;
+    const char * _serverKey;
+
+    passphrase_cb_userdata(const SSLConfigParams *params,const char *dialog, 
const char *cert, const char *key) :
+            _configParams(params), _serverDialog(dialog), _serverCert(cert), 
_serverKey(key) {}
+};
+
+// RAII implementation for struct termios
+struct ssl_termios : public  termios
+{
+  ssl_termios(int fd) {
+    _fd = -1;
+    // populate base class data
+    if (tcgetattr(fd, this) == 0) { // success
+       _fd = fd;
+    }
+    // save our copy
+    _initialAttr = *this;
+  }
+
+  ~ssl_termios() {
+    if (_fd != -1) {
+      tcsetattr(_fd, 0, &_initialAttr);
+    }
+  }
+
+  bool ok() {
+    return (_fd != -1);
+  }
+
+private:
+  int _fd;
+  struct termios _initialAttr;
+};
+
+static int
+ssl_getpassword(const char* prompt, char* buffer, int size)
+{
+  fprintf(stdout, "%s", prompt);
+
+  // disable echo and line buffering
+  ssl_termios tty_attr(STDIN_FILENO);
+
+  if (!tty_attr.ok()) {
+    return -1;
+  }
+
+  tty_attr.c_lflag &= ~ICANON; // no buffer, no backspace
+  tty_attr.c_lflag &= ~ECHO; // no echo
+  tty_attr.c_lflag &= ~ISIG; // no signal for ctrl-c
+
+  if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0) {
+    return -1;
+  }
+
+  int i = 0;
+  int ch = 0;
+  *buffer = 0;
+  while ((ch = getchar()) != '\n' && ch != EOF) {
+    // make sure room in buffer
+    if (i >= size - 1) {
+      return -1;
+    }
+
+    buffer[i] = ch;
+    buffer[++i] = 0;
+  }
+
+  return i;
+}
+
+static int
+ssl_private_key_passphrase_callback_exec(char *buf, int size, int rwflag, void 
*userdata)
+{
+  if (0 == size) {
+    return 0;
+  }
+
+  *buf = 0;
+  passphrase_cb_userdata *ud = static_cast<passphrase_cb_userdata *> 
(userdata);
+
+  Debug("ssl", "ssl_private_key_passphrase_callback_exec rwflag=%d 
serverDialog=%s", rwflag, ud->_serverDialog);
+
+  // only respond to reading private keys, not writing them (does ats even do 
that?)
+  if (0 == rwflag) {
+    // execute the dialog program and use the first line output as the 
passphrase
+    FILE *f = popen(ud->_serverDialog, "r");
+    if (f) {
+      if (fgets(buf, size, f)) {
+        // remove any ending CR or LF
+        for (char *pass = buf; *pass; pass++) {
+          if (*pass == '\n' || *pass == '\r') {
+            *pass = 0;
+            break;
+          }
+        }
+      }
+      pclose(f);
+    } else {// popen failed
+      Error("could not open dialog '%s' - %s", ud->_serverDialog, 
strerror(errno));
+    }
+  }
+  return strlen(buf);
+}
+
+static int
+ssl_private_key_passphrase_callback_builtin(char *buf, int size, int rwflag, 
void *userdata)
+{
+  if (0 == size) {
+    return 0;
+  }
+
+  *buf = 0;
+  passphrase_cb_userdata *ud = static_cast<passphrase_cb_userdata *> 
(userdata);
+
+  Debug("ssl", "ssl_private_key_passphrase_callback rwflag=%d 
serverDialog=%s", rwflag, ud->_serverDialog);
+
+  // only respond to reading private keys, not writing them (does ats even do 
that?)
+  if (0 == rwflag) {
+    // output request
+    fprintf(stdout, "Some of your private key files are encrypted for security 
reasons.\n");
+    fprintf(stdout, "In order to read them you have to provide the pass 
phrases.\n");
+    fprintf(stdout, "ssl_cert_name=%s", ud->_serverCert);
+    if (ud->_serverKey) { // output ssl_key_name if provided
+      fprintf(stdout, " ssl_key_name=%s", ud->_serverKey);
+    }
+    fprintf(stdout, "\n");
+    // get passphrase
+    // if error, then no passphrase
+    if (ssl_getpassword("Enter passphrase:", buf, size) <= 0) {
+      *buf = 0;
+    }
+    fprintf(stdout, "\n");
+  }
+  return strlen(buf);
+}
+
+static bool
+ssl_private_key_validate_exec(const char *cmdLine)
+{
+  if (NULL == cmdLine) {
+    errno = EINVAL;
+    return false;
+  }
+
+  bool bReturn = false;
+  char *cmdLineCopy = ats_strdup(cmdLine);
+  char *ptr = cmdLineCopy;
+
+  while(*ptr && !isspace(*ptr)) ++ptr;
+  *ptr = 0;
+  if (access(cmdLineCopy, X_OK) != -1) {
+    bReturn = true;
+  }
+  ats_free(cmdLineCopy);
+  return bReturn;
+}
+
 void
 SSLInitializeLibrary()
 {
@@ -415,9 +597,7 @@ SSLDefaultServerContext()
 SSL_CTX *
 SSLInitServerContext(
     const SSLConfigParams * params,
-    const char * serverCertPtr,
-    const char * serverCaCertPtr,
-    const char * serverKeyPtr)
+    const ssl_user_config & sslMultCertSettings)
 {
   int         session_id_context;
   int         server_verify_client;
@@ -445,10 +625,33 @@ SSLInitServerContext(
 #endif
   SSL_CTX_set_quiet_shutdown(ctx, 1);
 
+  // pass phrase dialog configuration
+  passphrase_cb_userdata ud(params, sslMultCertSettings.dialog, 
sslMultCertSettings.cert, sslMultCertSettings.key);
+
+  if (sslMultCertSettings.dialog) {
+    pem_password_cb * passwd_cb = NULL;
+    if (strncmp(sslMultCertSettings.dialog, "exec:", 5) == 0) {
+      ud._serverDialog = &sslMultCertSettings.dialog[5];
+      // validate the exec program
+      if (!ssl_private_key_validate_exec(ud._serverDialog)) {
+        SSLError("failed to access '%s' pass phrase program: %s", (const char 
*) ud._serverDialog, strerror(errno));
+        goto fail;
+      }
+      passwd_cb = ssl_private_key_passphrase_callback_exec;
+    } else if (strcmp(sslMultCertSettings.dialog, "builtin") == 0) {
+      passwd_cb = ssl_private_key_passphrase_callback_builtin;
+    } else { // unknown config
+      SSLError("unknown " SSL_KEY_DIALOG " configuration value '%s'", (const 
char *)sslMultCertSettings.dialog);
+      goto fail;
+    }
+    SSL_CTX_set_default_passwd_cb(ctx, passwd_cb);
+    SSL_CTX_set_default_passwd_cb_userdata(ctx, &ud);
+  }
+
   // XXX OpenSSL recommends that we should use 
SSL_CTX_use_certificate_chain_file() here. That API
   // also loads only the first certificate, but it allows the intermediate CA 
certificate chain to
   // be in the same file. SSL_CTX_use_certificate_chain_file() was added in 
OpenSSL 0.9.3.
-  completeServerCertPath = Layout::relative_to(params->serverCertPathOnly, 
serverCertPtr);
+  completeServerCertPath = Layout::relative_to(params->serverCertPathOnly, 
sslMultCertSettings.cert);
   if (!SSL_CTX_use_certificate_file(ctx, completeServerCertPath, 
SSL_FILETYPE_PEM)) {
     SSLError("failed to load certificate from %s", (const char 
*)completeServerCertPath);
     goto fail;
@@ -464,22 +667,22 @@ SSLInitServerContext(
   }
 
   // Now, load any additional certificate chains specified in this entry.
-  if (serverCaCertPtr) {
-    xptr<char> 
completeServerCertChainPath(Layout::relative_to(params->serverCertPathOnly, 
serverCaCertPtr));
+  if (sslMultCertSettings.ca) {
+    xptr<char> 
completeServerCertChainPath(Layout::relative_to(params->serverCertPathOnly, 
sslMultCertSettings.ca));
     if (!SSL_CTX_add_extra_chain_cert_file(ctx, completeServerCertChainPath)) {
       SSLError("failed to load certificate chain from %s", (const char 
*)completeServerCertChainPath);
       goto fail;
     }
   }
 
-  if (serverKeyPtr == NULL) {
+  if (!sslMultCertSettings.key) {
     // assume private key is contained in cert obtained from multicert file.
     if (!SSL_CTX_use_PrivateKey_file(ctx, completeServerCertPath, 
SSL_FILETYPE_PEM)) {
       SSLError("failed to load server private key from %s", (const char 
*)completeServerCertPath);
       goto fail;
     }
   } else if (params->serverKeyPathOnly != NULL) {
-    xptr<char> 
completeServerKeyPath(Layout::get()->relative_to(params->serverKeyPathOnly, 
serverKeyPtr));
+    xptr<char> 
completeServerKeyPath(Layout::get()->relative_to(params->serverKeyPathOnly, 
sslMultCertSettings.key));
     if (!SSL_CTX_use_PrivateKey_file(ctx, completeServerKeyPath, 
SSL_FILETYPE_PEM)) {
       SSLError("failed to load server private key from %s", (const char 
*)completeServerKeyPath);
       goto fail;
@@ -530,10 +733,16 @@ SSLInitServerContext(
       goto fail;
     }
   }
-
+#define SSL_CLEAR_PW_REFERENCES(UD,CTX) { \
+  memset(static_cast<void *>(&UD),0,sizeof(UD));\
+  SSL_CTX_set_default_passwd_cb(CTX, NULL);\
+  SSL_CTX_set_default_passwd_cb_userdata(CTX, NULL);\
+  }
+  SSL_CLEAR_PW_REFERENCES(ud,ctx)
   return ssl_context_enable_ecdh(ctx);
 
 fail:
+  SSL_CLEAR_PW_REFERENCES(ud,ctx)
   SSL_CTX_free(ctx);
   return NULL;
 }
@@ -704,18 +913,13 @@ static bool
 ssl_store_ssl_context(
     const SSLConfigParams * params,
     SSLCertLookup *         lookup,
-    xptr<char>& addr,
-    xptr<char>& cert,
-    xptr<char>& ca,
-    xptr<char>& key,
-    const int session_ticket_enabled,
-    xptr<char>& ticket_key_filename)
+    const ssl_user_config & sslMultCertSettings)
 {
   SSL_CTX *   ctx;
   xptr<char>  certpath;
   xptr<char>  session_key_path;
 
-  ctx = ssl_context_enable_sni(SSLInitServerContext(params, cert, ca, key), 
lookup);
+  ctx = ssl_context_enable_sni(SSLInitServerContext(params, 
sslMultCertSettings), lookup);
   if (!ctx) {
     return false;
   }
@@ -730,36 +934,36 @@ ssl_store_ssl_context(
   SSL_CTX_set_alpn_select_cb(ctx, SSLNetVConnection::select_next_protocol, 
NULL);
 #endif /* TS_USE_TLS_ALPN */
 
-  certpath = Layout::relative_to(params->serverCertPathOnly, cert);
+  certpath = Layout::relative_to(params->serverCertPathOnly, 
sslMultCertSettings.cert);
 
   // Index this certificate by the specified IP(v6) address. If the address is 
"*", make it the default context.
-  if (addr) {
-    if (strcmp(addr, "*") == 0) {
+  if (sslMultCertSettings.addr) {
+    if (strcmp(sslMultCertSettings.addr, "*") == 0) {
       lookup->ssl_default = ctx;
-      lookup->insert(ctx, addr);
+      lookup->insert(ctx, sslMultCertSettings.addr);
     } else {
       IpEndpoint ep;
 
-      if (ats_ip_pton(addr, &ep) == 0) {
-        Debug("ssl", "mapping '%s' to certificate %s", (const char *)addr, 
(const char *)certpath);
+      if (ats_ip_pton(sslMultCertSettings.addr, &ep) == 0) {
+        Debug("ssl", "mapping '%s' to certificate %s", (const char 
*)sslMultCertSettings.addr, (const char *)certpath);
         lookup->insert(ctx, ep);
       } else {
-        Error("'%s' is not a valid IPv4 or IPv6 address", (const char *)addr);
+        Error("'%s' is not a valid IPv4 or IPv6 address", (const char 
*)sslMultCertSettings.addr);
       }
     }
   }
 
 #if defined(SSL_OP_NO_TICKET)
   // Session tickets are enabled by default. Disable if explicitly requested.
-  if (session_ticket_enabled == 0) {
+  if (sslMultCertSettings.session_ticket_enabled == 0) {
     SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
     Debug("ssl", "ssl session ticket is disabled");
   }
 #endif
 
   // Load the session ticket key if session tickets are not disabled and we 
have key name.
-  if (session_ticket_enabled != 0 && ticket_key_filename) {
-    xptr<char> ticket_key_path(Layout::relative_to(params->serverCertPathOnly, 
ticket_key_filename));
+  if (sslMultCertSettings.session_ticket_enabled != 0 && 
sslMultCertSettings.ticket_key_filename) {
+    xptr<char> ticket_key_path(Layout::relative_to(params->serverCertPathOnly, 
sslMultCertSettings.ticket_key_filename));
     ssl_context_enable_tickets(ctx, ticket_key_path);
   }
 
@@ -779,12 +983,8 @@ ssl_store_ssl_context(
 static bool
 ssl_extract_certificate(
     const matcher_line * line_info,
-    xptr<char>& addr,   // IPv[64] address to match
-    xptr<char>& cert,   // certificate
-    xptr<char>& ca,     // CA public certificate
-    xptr<char>& key,    // Private key
-    int&  session_ticket_enabled,  // session ticket enabled
-    xptr<char>& ticket_key_filename) // session key file. [key_name (16Byte) + 
HMAC_secret (16Byte) + AES_key (16Byte)]
+    ssl_user_config & sslMultCertSettings)
+
 {
   for (int i = 0; i < MATCHER_MAX_TOKENS; ++i) {
     const char * label;
@@ -798,31 +998,34 @@ ssl_extract_certificate(
     }
 
     if (strcasecmp(label, SSL_IP_TAG) == 0) {
-      addr = ats_strdup(value);
+      sslMultCertSettings.addr = ats_strdup(value);
     }
 
     if (strcasecmp(label, SSL_CERT_TAG) == 0) {
-      cert = ats_strdup(value);
+      sslMultCertSettings.cert = ats_strdup(value);
     }
 
     if (strcasecmp(label, SSL_CA_TAG) == 0) {
-      ca = ats_strdup(value);
+      sslMultCertSettings.ca = ats_strdup(value);
     }
 
     if (strcasecmp(label, SSL_PRIVATE_KEY_TAG) == 0) {
-      key = ats_strdup(value);
+      sslMultCertSettings.key = ats_strdup(value);
     }
 
     if (strcasecmp(label, SSL_SESSION_TICKET_ENABLED) == 0) {
-      session_ticket_enabled = atoi(value);
+      sslMultCertSettings.session_ticket_enabled = atoi(value);
     }
 
     if (strcasecmp(label, SSL_SESSION_TICKET_KEY_FILE_TAG) == 0) {
-      ticket_key_filename = ats_strdup(value);
+      sslMultCertSettings.ticket_key_filename = ats_strdup(value);
     }
-  }
 
-  if (!cert) {
+    if (strcasecmp(label, SSL_KEY_DIALOG) == 0) {
+      sslMultCertSettings.dialog = ats_strdup(value);
+    }
+  }
+  if (!sslMultCertSettings.cert) {
     Error("missing %s tag", SSL_CERT_TAG);
     return false;
   }
@@ -875,12 +1078,7 @@ SSLParseCertificateConfiguration(
     }
 
     if (*line != '\0' && *line != '#') {
-      xptr<char> addr;
-      xptr<char> cert;
-      xptr<char> ca;
-      xptr<char> key;
-      int session_ticket_enabled = -1;
-      xptr<char> ticket_key_filename;
+      ssl_user_config sslMultiCertSettings;
       const char * errPtr;
 
       errPtr = parseConfigLine(line, &line_info, &sslCertTags);
@@ -890,8 +1088,8 @@ SSLParseCertificateConfiguration(
                      __func__, params->configFilePath, line_num, errPtr);
         REC_SignalError(errBuf, alarmAlready);
       } else {
-        if (ssl_extract_certificate(&line_info, addr, cert, ca, key, 
session_ticket_enabled, ticket_key_filename)) {
-          if (!ssl_store_ssl_context(params, lookup, addr, cert, ca, key, 
session_ticket_enabled, ticket_key_filename)) {
+        if (ssl_extract_certificate(&line_info, sslMultiCertSettings)) {
+          if (!ssl_store_ssl_context(params, lookup, sslMultiCertSettings)) {
             Error("failed to load SSL certificate specification from %s line 
%u",
                 params->configFilePath, line_num);
           }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/e0c35aa8/proxy/config/ssl_multicert.config.default
----------------------------------------------------------------------
diff --git a/proxy/config/ssl_multicert.config.default 
b/proxy/config/ssl_multicert.config.default
index be60994..b6dff3c 100644
--- a/proxy/config/ssl_multicert.config.default
+++ b/proxy/config/ssl_multicert.config.default
@@ -28,7 +28,7 @@
 #   square brackets if they have a port, eg, [::1]:80.
 #
 # ssl_key_name=FILENAME
-#   The name of the file containg the private key for this certificate.
+#   The name of the file containing the private key for this certificate.
 #   If the key is contained in the certificate file, this field can be
 #   omitted.
 #
@@ -40,9 +40,16 @@
 #   The name of the file containing the TLS certificate. This is the
 #   only field that is required to be present.
 #
+# ssl_key_dialog=[builtin|exec:/path/to/program]
+#   Method used to provide a pass phrase for encrypted private keys.
+#   Two options are supported: builtin and exec
+#     builtin - Requests passphrase via stdin/stdout. Useful for debugging.
+#     exec: - Executes a program and uses the stdout output for the pass
+#       phrase.
+#
 # Examples:
 #   ssl_cert_name=foo.pem
 #   dest_ip=*  ssl_cert_name=bar.pem ssl_key_name=barKey.pem
 #   dest_ip=209.131.48.79      ssl_cert_name=server.pem 
ssl_key_name=serverKey.pem
 #   dest_ip=10.0.0.1:99 ssl_cert_name=port99.pem
-
+#   ssl_cert_name=foo.pem ssl_key_dialog="exec:/usr/bin/mypass foo 'ba r'"

Reply via email to