You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ti...@apache.org on 2016/07/04 16:42:57 UTC

[1/5] mesos git commit: Extended utilities to render certificate extension for IP.

Repository: mesos
Updated Branches:
  refs/heads/master e5f73dc7a -> 92713431c


Extended utilities to render certificate extension for IP.

Adds the ability to render a subject alternative name based on a given
IP address within a X509 certificate extension. Additionally the
libprocess test suite makes use of this feature.

Review: https://reviews.apache.org/r/49400/


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

Branch: refs/heads/master
Commit: 6133e72ccd777c541036a2cc80487d0c842c836b
Parents: e5f73dc
Author: Till Toenshoff <to...@me.com>
Authored: Mon Jul 4 18:32:12 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Mon Jul 4 18:32:12 2016 +0200

----------------------------------------------------------------------
 .../libprocess/include/process/ssl/gtest.hpp    |  3 +-
 .../include/process/ssl/utilities.hpp           | 10 ++-
 3rdparty/libprocess/src/ssl/utilities.cpp       | 81 +++++++++++++++++++-
 3 files changed, 90 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/6133e72c/3rdparty/libprocess/include/process/ssl/gtest.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/ssl/gtest.hpp b/3rdparty/libprocess/include/process/ssl/gtest.hpp
index 5435ddd..3faf4d6 100644
--- a/3rdparty/libprocess/include/process/ssl/gtest.hpp
+++ b/3rdparty/libprocess/include/process/ssl/gtest.hpp
@@ -192,7 +192,8 @@ protected:
         None(),
         1,
         365,
-        hostname.get());
+        hostname.get(),
+        net::IP(INADDR_LOOPBACK));
 
     if (certificate.isError()) {
       cleanup("Could not generate certificate: " + certificate.error());

http://git-wip-us.apache.org/repos/asf/mesos/blob/6133e72c/3rdparty/libprocess/include/process/ssl/utilities.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/ssl/utilities.hpp b/3rdparty/libprocess/include/process/ssl/utilities.hpp
index ad9ec5d..c2f64a9 100644
--- a/3rdparty/libprocess/include/process/ssl/utilities.hpp
+++ b/3rdparty/libprocess/include/process/ssl/utilities.hpp
@@ -18,6 +18,7 @@
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 
+#include <stout/ip.hpp>
 #include <stout/nothing.hpp>
 #include <stout/path.hpp>
 #include <stout/try.hpp>
@@ -56,7 +57,9 @@ Try<EVP_PKEY*> generate_private_rsa_key(
  * @param parent_certificate. Otherwise, it is assumed this is a
  * self-signed certificate in which case the @param subject_key must
  * be the same as the @param sign_key, and the issuer name will be the
- * same as the subject name.
+ * same as the subject name. If @param ip is provided, then the
+ * certificate will use the ip for a subject alternative name iPAddress
+ * extension.
  *
  * @param subject_key The key that will be made public by the
  *     certificate.
@@ -68,6 +71,8 @@ Try<EVP_PKEY*> generate_private_rsa_key(
  *     certificate will be valid.
  * @param hostname An optional hostname used to set the common name of
  *     the certificate.
+ * @param ip An optional IP used to set the subject alternative name
+ *     iPAddress of the certificate extension.
  *
  * @return A pointer to an X509 certificate if successful otherwise an
  *     Error.
@@ -78,7 +83,8 @@ Try<X509*> generate_x509(
     const Option<X509*>& parent_certificate = None(),
     int serial = 1,
     int days = 365,
-    Option<std::string> hostname = None());
+    Option<std::string> hostname = None(),
+    const Option<net::IP>& ip = None());
 
 
 /**

http://git-wip-us.apache.org/repos/asf/mesos/blob/6133e72c/3rdparty/libprocess/src/ssl/utilities.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/ssl/utilities.cpp b/3rdparty/libprocess/src/ssl/utilities.cpp
index 02bfd17..8aec613 100644
--- a/3rdparty/libprocess/src/ssl/utilities.cpp
+++ b/3rdparty/libprocess/src/ssl/utilities.cpp
@@ -88,7 +88,8 @@ Try<X509*> generate_x509(
     const Option<X509*>& parent_certificate,
     int serial,
     int days,
-    Option<std::string> hostname)
+    Option<std::string> hostname,
+    const Option<net::IP>& ip)
 {
   Option<X509_NAME*> issuer_name = None();
   if (parent_certificate.isNone()) {
@@ -207,6 +208,84 @@ Try<X509*> generate_x509(
     return Error("Failed to set issuer name: X509_set_issuer_name");
   }
 
+  if (ip.isSome()) {
+    // Add an X509 extension with an IP for subject alternative name.
+
+    STACK_OF(GENERAL_NAME)* alt_name_stack = sk_GENERAL_NAME_new_null();
+    if (alt_name_stack == nullptr) {
+      X509_free(x509);
+      return Error("Failed to create a stack: sk_GENERAL_NAME_new_null");
+    }
+
+    GENERAL_NAME* alt_name = GENERAL_NAME_new();
+    if (alt_name == nullptr) {
+      sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
+      X509_free(x509);
+      return Error("Failed to create GENERAL_NAME: GENERAL_NAME_new");
+    }
+
+    alt_name->type = GEN_IPADD;
+
+    ASN1_STRING* alt_name_str = ASN1_STRING_new();
+    if (alt_name_str == nullptr) {
+      GENERAL_NAME_free(alt_name);
+      sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
+      X509_free(x509);
+      return Error("Failed to create alternative name: ASN1_STRING_new");
+    }
+
+    Try<in_addr> in = ip.get().in();
+
+    if (in.isError()) {
+      ASN1_STRING_free(alt_name_str);
+      GENERAL_NAME_free(alt_name);
+      sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
+      X509_free(x509);
+      return Error("Failed to get IP/4 address");
+    }
+
+    // For `iPAddress` we hand over a binary value as part of the
+    // specification.
+    if (ASN1_STRING_set(
+            alt_name_str,
+            &in.get().s_addr,
+            sizeof(in_addr_t)) == 0) {
+      ASN1_STRING_free(alt_name_str);
+      GENERAL_NAME_free(alt_name);
+      sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
+      X509_free(x509);
+      return Error("Failed to set alternative name: ASN1_STRING_set");
+    }
+
+    // We are transferring ownership of 'alt_name_str` towards the
+    // `ASN1_OCTET_STRING` here.
+    alt_name->d.iPAddress = alt_name_str;
+
+    // We try to transfer ownership of 'alt_name` towards the
+    // `STACK_OF(GENERAL_NAME)` here.
+    if (sk_GENERAL_NAME_push(alt_name_stack, alt_name) == 0) {
+      GENERAL_NAME_free(alt_name);
+      sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
+      X509_free(x509);
+      return Error("Failed to push alternative name: sk_GENERAL_NAME_push");
+    }
+
+    // We try to transfer the ownership of `alt_name_stack` towards the
+    // `X509` here.
+    if (X509_add1_ext_i2d(
+            x509,
+            NID_subject_alt_name,
+            alt_name_stack,
+            0,
+            0) == 0) {
+      sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
+      X509_free(x509);
+      return Error("Failed to set subject alternative name: X509_add1_ext_i2d");
+    }
+
+    sk_GENERAL_NAME_pop_free(alt_name_stack, GENERAL_NAME_free);
+  }
+
   // Sign the certificate with the sign key.
   if (X509_sign(x509, sign_key, EVP_sha1()) == 0) {
     X509_free(x509);


[3/5] mesos git commit: Added tests for IP based certificate validation.

Posted by ti...@apache.org.
Added tests for IP based certificate validation.

Review: https://reviews.apache.org/r/49402/


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

Branch: refs/heads/master
Commit: ae0504c33efc126b9b19755cbc7839a38de067f5
Parents: 36a3c64
Author: Till Toenshoff <to...@me.com>
Authored: Mon Jul 4 18:34:03 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Mon Jul 4 18:34:03 2016 +0200

----------------------------------------------------------------------
 3rdparty/libprocess/include/process/ssl/gtest.hpp |  3 ++-
 3rdparty/libprocess/src/tests/ssl_tests.cpp       | 16 ++++++++++++----
 2 files changed, 14 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/ae0504c3/3rdparty/libprocess/include/process/ssl/gtest.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/ssl/gtest.hpp b/3rdparty/libprocess/include/process/ssl/gtest.hpp
index 3faf4d6..a929cc9 100644
--- a/3rdparty/libprocess/include/process/ssl/gtest.hpp
+++ b/3rdparty/libprocess/include/process/ssl/gtest.hpp
@@ -267,7 +267,8 @@ protected:
  * SSLTest::launch_client that factor out common behavior used in
  * tests.
  */
-class SSLTest : public SSLTemporaryDirectoryTest
+class SSLTest : public SSLTemporaryDirectoryTest,
+                public ::testing::WithParamInterface<const char*>
 {
 protected:
   SSLTest() : data("Hello World!") {}

http://git-wip-us.apache.org/repos/asf/mesos/blob/ae0504c3/3rdparty/libprocess/src/tests/ssl_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/ssl_tests.cpp b/3rdparty/libprocess/src/tests/ssl_tests.cpp
index 6fc9038..72432ec 100644
--- a/3rdparty/libprocess/src/tests/ssl_tests.cpp
+++ b/3rdparty/libprocess/src/tests/ssl_tests.cpp
@@ -102,6 +102,11 @@ Future<Nothing> await_subprocess(
 }
 
 
+INSTANTIATE_TEST_CASE_P(SSLVerifyIPAdd,
+                        SSLTest,
+                        ::testing::Values("false", "true"));
+
+
 // Ensure that we can't create an SSL socket when SSL is not enabled.
 TEST(SSL, Disabled)
 {
@@ -113,7 +118,7 @@ TEST(SSL, Disabled)
 
 // Test a basic back-and-forth communication within the same OS
 // process.
-TEST_F(SSLTest, BasicSameProcess)
+TEST_P(SSLTest, BasicSameProcess)
 {
   os::setenv("SSL_ENABLED", "true");
   os::setenv("SSL_KEY_FILE", key_path().string());
@@ -121,6 +126,7 @@ TEST_F(SSLTest, BasicSameProcess)
   os::setenv("SSL_REQUIRE_CERT", "true");
   os::setenv("SSL_CA_DIR", os::getcwd());
   os::setenv("SSL_CA_FILE", certificate_path().string());
+  os::setenv("SSL_VERIFY_IPADD", GetParam());
 
   openssl::reinitialize();
 
@@ -348,20 +354,22 @@ TEST_F(SSLTest, VerifyCertificate)
 // Ensure that a certificate that WAS generated using the certificate
 // authority is NOT allowed to communicate when the SSL_REQUIRE_CERT
 // flag is enabled.
-TEST_F(SSLTest, RequireCertificate)
+TEST_P(SSLTest, RequireCertificate)
 {
   Try<Socket> server = setup_server({
       {"SSL_ENABLED", "true"},
       {"SSL_KEY_FILE", key_path().string()},
       {"SSL_CERT_FILE", certificate_path().string()},
-      {"SSL_REQUIRE_CERT", "true"}});
+      {"SSL_REQUIRE_CERT", "true"},
+      {"SSL_VERIFY_IPADD", GetParam()}});
   ASSERT_SOME(server);
 
   Try<Subprocess> client = launch_client({
       {"SSL_ENABLED", "true"},
       {"SSL_KEY_FILE", key_path().string()},
       {"SSL_CERT_FILE", certificate_path().string()},
-      {"SSL_REQUIRE_CERT", "true"}},
+      {"SSL_REQUIRE_CERT", "true"},
+      {"SSL_VERIFY_IPADD", GetParam()}},
       server.get(),
       true);
   ASSERT_SOME(client);


[2/5] mesos git commit: Updated certificate validation to check 'IP Address' SAN.

Posted by ti...@apache.org.
Updated certificate validation to check 'IP Address' SAN.

Allows the verification of X509 certificates based on an IP address
instead of a hostname. Introduces a new environment variable;
\`SSL_VERIFY_IPADD\` which, when set to \`true\` will enable the
peer certificate verification to additionally rely on the IP
address of a connection.

Review: https://reviews.apache.org/r/49401/


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

Branch: refs/heads/master
Commit: 36a3c6494be91e7a9b898c3c8eebe59883c050e4
Parents: 6133e72
Author: Till Toenshoff <to...@me.com>
Authored: Mon Jul 4 18:32:40 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Mon Jul 4 18:32:40 2016 +0200

----------------------------------------------------------------------
 3rdparty/libprocess/src/libevent_ssl_socket.cpp |  14 +-
 3rdparty/libprocess/src/libevent_ssl_socket.hpp |   1 +
 3rdparty/libprocess/src/openssl.cpp             | 142 ++++++++++++++-----
 3rdparty/libprocess/src/openssl.hpp             |   8 +-
 4 files changed, 125 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/36a3c649/3rdparty/libprocess/src/libevent_ssl_socket.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/libevent_ssl_socket.cpp b/3rdparty/libprocess/src/libevent_ssl_socket.cpp
index 19d9ae5..2e7f332 100644
--- a/3rdparty/libprocess/src/libevent_ssl_socket.cpp
+++ b/3rdparty/libprocess/src/libevent_ssl_socket.cpp
@@ -396,7 +396,7 @@ void LibeventSSLSocketImpl::event_callback(short events)
     // Do post-validation of connection.
     SSL* ssl = bufferevent_openssl_get_ssl(bev);
 
-    Try<Nothing> verify = openssl::verify(ssl, peer_hostname);
+    Try<Nothing> verify = openssl::verify(ssl, peer_hostname, peer_ip);
     if (verify.isError()) {
       VLOG(1) << "Failed connect, verification error: " << verify.error();
       SSL_free(ssl);
@@ -513,7 +513,7 @@ Future<Nothing> LibeventSSLSocketImpl::connect(const Address& address)
   }
 
   // Try and determine the 'peer_hostname' from the address we're
-  // connecting to in order to properly verify the SSL connection later.
+  // connecting to in order to properly verify the certificate later.
   const Try<string> hostname = address.hostname();
 
   if (hostname.isError()) {
@@ -523,6 +523,10 @@ Future<Nothing> LibeventSSLSocketImpl::connect(const Address& address)
     peer_hostname = hostname.get();
   }
 
+  // Determine the 'peer_ip' from the address we're connecting to in
+  // order to properly verify the certificate later.
+  peer_ip = address.ip;
+
   // Optimistically construct a 'ConnectRequest' and future.
   Owned<ConnectRequest> request(new ConnectRequest());
   Future<Nothing> future = request->promise.future();
@@ -1023,8 +1027,10 @@ void LibeventSSLSocketImpl::accept_SSL_callback(AcceptRequest* request)
           // post-verification. First, we need to determine the peer
           // hostname.
           Option<string> peer_hostname = None();
+
           if (request->ip.isSome()) {
             Try<string> hostname = net::getHostname(request->ip.get());
+
             if (hostname.isError()) {
               VLOG(2) << "Could not determine hostname of peer: "
                       << hostname.error();
@@ -1037,7 +1043,9 @@ void LibeventSSLSocketImpl::accept_SSL_callback(AcceptRequest* request)
           SSL* ssl = bufferevent_openssl_get_ssl(bev);
           CHECK_NOTNULL(ssl);
 
-          Try<Nothing> verify = openssl::verify(ssl, peer_hostname);
+          Try<Nothing> verify =
+            openssl::verify(ssl, peer_hostname, request->ip);
+
           if (verify.isError()) {
             VLOG(1) << "Failed accept, verification error: " << verify.error();
             request->promise.fail(verify.error());

http://git-wip-us.apache.org/repos/asf/mesos/blob/36a3c649/3rdparty/libprocess/src/libevent_ssl_socket.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/libevent_ssl_socket.hpp b/3rdparty/libprocess/src/libevent_ssl_socket.hpp
index 1dbdaa8..4d376d8 100644
--- a/3rdparty/libprocess/src/libevent_ssl_socket.hpp
+++ b/3rdparty/libprocess/src/libevent_ssl_socket.hpp
@@ -178,6 +178,7 @@ private:
   Queue<Future<Socket>> accept_queue;
 
   Option<std::string> peer_hostname;
+  Option<net::IP> peer_ip;
 
   // Socket descriptor/handle used by libevent_ssl.
   // Ownership semantics:

http://git-wip-us.apache.org/repos/asf/mesos/blob/36a3c649/3rdparty/libprocess/src/openssl.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/openssl.cpp b/3rdparty/libprocess/src/openssl.cpp
index 0f62aa6..63916ff 100644
--- a/3rdparty/libprocess/src/openssl.cpp
+++ b/3rdparty/libprocess/src/openssl.cpp
@@ -80,6 +80,12 @@ Flags::Flags()
       "certificate implies verifying it.",
       false);
 
+  add(&Flags::verify_ipadd,
+      "verify_ipadd",
+      "Enable IP address verification in subject alternative name certificate "
+      "extension.",
+      false);
+
   add(&Flags::verification_depth,
       "verification_depth",
       "Maximum depth for the certificate chain verification that shall be "
@@ -401,6 +407,11 @@ void reinitialize()
             << "verification";
   }
 
+  if (ssl_flags->verify_ipadd) {
+    VLOG(2) << "Will use IP address verification in subject alternative name "
+            << "certificate extension.";
+  }
+
   if (ssl_flags->require_cert && !ssl_flags->verify_cert) {
     // Requiring a certificate implies that is should be verified.
     ssl_flags->verify_cert = true;
@@ -543,7 +554,10 @@ SSL_CTX* context()
 }
 
 
-Try<Nothing> verify(const SSL* const ssl, const Option<string>& hostname)
+Try<Nothing> verify(
+    const SSL* const ssl,
+    const Option<string>& hostname,
+    const Option<net::IP>& ip)
 {
   // Return early if we don't need to verify.
   if (!ssl_flags->verify_cert) {
@@ -565,7 +579,7 @@ Try<Nothing> verify(const SSL* const ssl, const Option<string>& hostname)
     return Error("Could not verify peer certificate");
   }
 
-  if (hostname.isNone()) {
+  if (!ssl_flags->verify_ipadd && hostname.isNone()) {
     X509_free(cert);
     return ssl_flags->require_cert
       ? Error("Cannot verify peer certificate: peer hostname unknown")
@@ -589,24 +603,62 @@ Try<Nothing> verify(const SSL* const ssl, const Option<string>& hostname)
     for (int i = 0; i < san_names_num; i++) {
       const GENERAL_NAME* current_name = sk_GENERAL_NAME_value(san_names, i);
 
-      if (current_name->type == GEN_DNS) {
-        // Current name is a DNS name, let's check it.
-        const string dns_name =
-          reinterpret_cast<char*>(ASN1_STRING_data(current_name->d.dNSName));
+      switch(current_name->type) {
+        case GEN_DNS: {
+          if (hostname.isSome()) {
+            // Current name is a DNS name, let's check it.
+            const string dns_name =
+              reinterpret_cast<char*>(ASN1_STRING_data(
+                  current_name->d.dNSName));
+
+            // Make sure there isn't an embedded NUL character in the DNS name.
+            const size_t length = ASN1_STRING_length(current_name->d.dNSName);
+            if (length != dns_name.length()) {
+              sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+              X509_free(cert);
+              return Error(
+                  "X509 certificate malformed: "
+                  "embedded NUL character in DNS name");
+            } else {
+              VLOG(2) << "Matching dNSName(" << i << "): " << dns_name;
+
+              // Compare expected hostname with the DNS name.
+              if (hostname.get() == dns_name) {
+                sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+                X509_free(cert);
+
+                VLOG(2) << "dNSName match found for " << hostname.get();
+
+                return Nothing();
+              }
+            }
+          }
+          break;
+        }
+        case GEN_IPADD: {
+          if (ssl_flags->verify_ipadd && ip.isSome()) {
+            // Current name is an IPAdd, let's check it.
+            const ASN1_OCTET_STRING* current_ipadd = current_name->d.iPAddress;
 
-        // Make sure there isn't an embedded NUL character in the DNS name.
-        const size_t length = ASN1_STRING_length(current_name->d.dNSName);
-        if (length != dns_name.length()) {
-          sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
-          X509_free(cert);
-          return Error(
-            "X509 certificate malformed: embedded NUL character in DNS name");
-        } else { // Compare expected hostname with the DNS name.
-          if (hostname.get() == dns_name) {
-            sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
-            X509_free(cert);
-            return Nothing();
+            if (current_ipadd->type == V_ASN1_OCTET_STRING &&
+                current_ipadd->data != nullptr &&
+                current_ipadd->length == sizeof(uint32_t)) {
+              const net::IP ip_add(ntohl(
+                  *reinterpret_cast<uint32_t*>(current_ipadd->data)));
+
+              VLOG(2) << "Matching iPAddress(" << i << "): " << ip_add;
+
+              if (ip.get() == ip_add) {
+                sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
+                X509_free(cert);
+
+                VLOG(2) << "iPAddress match found for " << ip.get();
+
+                return Nothing();
+              }
+            }
           }
+          break;
         }
       }
     }
@@ -614,34 +666,52 @@ Try<Nothing> verify(const SSL* const ssl, const Option<string>& hostname)
     sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
   }
 
-  // If we still haven't verified the hostname, try doing it via
-  // the certificate subject name.
-  X509_NAME* name = X509_get_subject_name(cert);
+  if (hostname.isSome()) {
+    // If we still haven't verified the hostname, try doing it via
+    // the certificate subject name.
+    X509_NAME* name = X509_get_subject_name(cert);
+
+    if (name != nullptr) {
+      char text[_POSIX_HOST_NAME_MAX] {};
 
-  if (name != nullptr) {
-    char text[_POSIX_HOST_NAME_MAX] {};
+      if (X509_NAME_get_text_by_NID(
+              name,
+              NID_commonName,
+              text,
+              sizeof(text)) > 0) {
+        VLOG(2) << "Matching common name: " << text;
+
+        if (hostname.get() != text) {
+          X509_free(cert);
+          return Error(
+            "Presented Certificate Name: " + stringify(text) +
+            " does not match peer hostname name: " + hostname.get());
+        }
+
+        VLOG(2) << "Common name match found for " << hostname.get();
 
-    if (X509_NAME_get_text_by_NID(
-            name,
-            NID_commonName,
-            text,
-            sizeof(text)) > 0) {
-      if (hostname.get() != text) {
         X509_free(cert);
-        return Error(
-          "Presented Certificate Name: " + stringify(text) +
-          " does not match peer hostname name: " + hostname.get());
+        return Nothing();
       }
-
-      X509_free(cert);
-      return Nothing();
     }
   }
 
   // If we still haven't exited, we haven't verified it, and we give up.
   X509_free(cert);
+
+  std::vector<string> details;
+
+  if (hostname.isSome()) {
+    details.push_back("hostname " + hostname.get());
+  }
+
+  if (ip.isSome()) {
+    details.push_back("IP " + stringify(ip.get()));
+  }
+
   return Error(
-    "Could not verify presented certificate with hostname " + hostname.get());
+      "Could not verify presented certificate with " +
+      strings::join(", ", details));
 }
 
 } // namespace openssl {

http://git-wip-us.apache.org/repos/asf/mesos/blob/36a3c649/3rdparty/libprocess/src/openssl.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/openssl.hpp b/3rdparty/libprocess/src/openssl.hpp
index 7d55025..68f8897 100644
--- a/3rdparty/libprocess/src/openssl.hpp
+++ b/3rdparty/libprocess/src/openssl.hpp
@@ -18,6 +18,7 @@
 #include <string>
 
 #include <stout/flags.hpp>
+#include <stout/ip.hpp>
 #include <stout/nothing.hpp>
 #include <stout/option.hpp>
 #include <stout/try.hpp>
@@ -39,6 +40,7 @@ public:
   Option<std::string> key_file;
   bool verify_cert;
   bool require_cert;
+  bool verify_ipadd;
   unsigned int verification_depth;
   Option<std::string> ca_dir;
   Option<std::string> ca_file;
@@ -61,6 +63,7 @@ const Flags& flags();
 //    SSL_KEY_FILE=(path to key)
 //    SSL_VERIFY_CERT=(false|0,true|1)
 //    SSL_REQUIRE_CERT=(false|0,true|1)
+//    SSL_VERIFY_IPADD=(false|0,true|1)
 //    SSL_VERIFY_DEPTH=(4)
 //    SSL_CA_DIR=(path to CA directory)
 //    SSL_CA_FILE=(path to CA file)
@@ -82,7 +85,10 @@ SSL_CTX* context();
 
 // Verify that the hostname is properly associated with the peer
 // certificate associated with the specified SSL connection.
-Try<Nothing> verify(const SSL* const ssl, const Option<std::string>& hostname);
+Try<Nothing> verify(
+    const SSL* const ssl,
+    const Option<std::string>& hostname = None(),
+    const Option<net::IP>& ip = None());
 
 } // namespace openssl {
 } // namespace network {


[4/5] mesos git commit: Updated CHANGELOG for MESOS-5724.

Posted by ti...@apache.org.
Updated CHANGELOG for MESOS-5724.

Review: https://reviews.apache.org/r/49411/


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

Branch: refs/heads/master
Commit: 2585fedca4d148508a886f7ea6391fd77fa8b308
Parents: ae0504c
Author: Till Toenshoff <to...@me.com>
Authored: Mon Jul 4 18:34:28 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Mon Jul 4 18:34:28 2016 +0200

----------------------------------------------------------------------
 CHANGELOG | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/2585fedc/CHANGELOG
----------------------------------------------------------------------
diff --git a/CHANGELOG b/CHANGELOG
index 47a9dcb..cacfb5b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -103,6 +103,9 @@ This release contains the following new features:
     resource. This initial support works when there is no container filesystem
     isolation in use. Improvements to the support to come in future releases.
 
+  * [MESOS-5724] - SSL certificate validation allows for additional IP address
+    subject alternative name extension verification.
+
 Deprecations:
   * [MESOS-2281] - Deprecated the plain text format for credentials in favor of
     the JSON format.


[5/5] mesos git commit: Updated SSL.md with 'SSL_VERIFY_IPADD'.

Posted by ti...@apache.org.
Updated SSL.md with 'SSL_VERIFY_IPADD'.

Review: https://reviews.apache.org/r/49412/


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

Branch: refs/heads/master
Commit: 92713431c058984bc439737c647cd162ebce8836
Parents: 2585fed
Author: Till Toenshoff <to...@me.com>
Authored: Mon Jul 4 18:34:48 2016 +0200
Committer: Till Toenshoff <to...@me.com>
Committed: Mon Jul 4 18:34:48 2016 +0200

----------------------------------------------------------------------
 docs/ssl.md | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/92713431/docs/ssl.md
----------------------------------------------------------------------
diff --git a/docs/ssl.md b/docs/ssl.md
index 5eef9fd..64f63b7 100644
--- a/docs/ssl.md
+++ b/docs/ssl.md
@@ -52,6 +52,9 @@ Enforce that certificates must be presented by connecting clients. This means al
 #### SSL_VERIFY_DEPTH=(N) [default=4]
 The maximum depth used to verify certificates. The default is 4. See the OpenSSL documentation or contact your system administrator to learn why you may want to change this.
 
+#### SSL_VERIFY_IPADD=(false|0,true|1) [default=false|0]
+Enable IP address verification in the certificate subject alternative name extension. When set to `true` the peer certificate verification will additionally use the IP address of a peer connection. When a hostname of the peer as well as its IP address are available, the validation will succeed when either the hostname or the IP match.
+
 #### SSL_CA_DIR=(path to CA directory)
 The directory used to find the certificate authority / authorities. You can specify `SSL_CA_DIR` or `SSL_CA_FILE` depending on how you want to restrict your certificate authorization.