From: Steffan Karger <steffan.kar...@fox-it.com>

Add support for PolarSSL-1.2, which has changed the API in several places. This
is a minimal port: PolarSSL-1.2 works as well as PolarSSL-1.1, but the new
features have not been enabled.

Blacklist PolarSSL-1.[0-2] for bugs when verifying certificate chains

Signed-off-by: Joachim Schipper <joachim.schip...@fox-it.com>
---
 configure.ac                      |    2 ++
 src/openvpn/crypto_polarssl.h     |    4 +++
 src/openvpn/options.c             |    4 +++
 src/openvpn/ssl_polarssl.c        |   29 ++++++++++++++++++++--
 src/openvpn/ssl_polarssl.h        |    4 +++
 src/openvpn/ssl_verify_polarssl.c |   49 ++++++++++++++++++++++++++++---------
 src/openvpn/ssl_verify_polarssl.h |   45 ++++++++++++++++++++++++++++------
 7 files changed, 115 insertions(+), 22 deletions(-)

diff --git a/configure.ac b/configure.ac
index 2f780b7..97e5d09 100644
--- a/configure.ac
+++ b/configure.ac
@@ -807,6 +807,8 @@ if test "${with_crypto_library}" = "polarssl" ; then
                        [[
 #if POLARSSL_VERSION_NUMBER < 0x01010000
 #error invalid version
+#elif POLARSSL_VERSION_NUMBER >= 0x01020000 && POLARSSL_VERSION_NUMBER < 
0x01020300
+#error PolarSSL-1.2.x before 1.2.3 is incompatible with OpenVPN
 #endif
                        ]]
                )],
diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h
index bfabb91..e3dee5c 100644
--- a/src/openvpn/crypto_polarssl.h
+++ b/src/openvpn/crypto_polarssl.h
@@ -60,7 +60,11 @@ typedef md_context_t hmac_ctx_t;
 #define OPENVPN_MODE_OFB       POLARSSL_MODE_OFB

 /** Cipher is in CFB mode */
+#if POLARSSL_VERSION_NUMBER < 0x01020000
 #define OPENVPN_MODE_CFB       POLARSSL_MODE_CFB128
+#else
+#define OPENVPN_MODE_CFB       POLARSSL_MODE_CFB
+#endif

 /** Cipher should encrypt */
 #define OPENVPN_OP_ENCRYPT     POLARSSL_ENCRYPT
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 8ca41a3..429f864 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -827,7 +827,11 @@ init_options (struct options *o, const bool init_gc)
   o->server_poll_timeout = 0;
 #endif
 #ifdef ENABLE_CRYPTO
+#ifdef ENABLE_CRYPTO_POLARSSL
+  o->ciphername = "BLOWFISH-CBC";
+#else
   o->ciphername = "BF-CBC";
+#endif
   o->ciphername_defined = true;
   o->authname = "SHA1";
   o->authname_defined = true;
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
index 210bbab..9e99675 100644
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_polarssl.c
@@ -44,6 +44,7 @@
 #include "manage.h"
 #include "ssl_common.h"

+#include <polarssl/version.h>
 #include <polarssl/sha2.h>
 #include <polarssl/havege.h>

@@ -65,6 +66,8 @@ tls_clear_error()
 {
 }

+#if POLARSSL_VERSION_NUMBER < 0x01020000
+/* The default list of ciphers is already initialized in PolarSSL-1.2.0+ */
 static int default_ciphersuites[] =
 {
     SSL_EDH_RSA_AES_256_SHA,
@@ -81,6 +84,7 @@ static int default_ciphersuites[] =
     SSL_RSA_RC4_128_MD5,
     0
 };
+#endif

 void
 tls_ctx_server_new(struct tls_root_ctx *ctx)
@@ -514,27 +518,43 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,

       ssl_set_rng (ks_ssl->ctx, ctr_drbg_random, rand_ctx_get());

+#if POLARSSL_VERSION_NUMBER < 0x01020000
+      /* Handled implicitly in PolarSSL-1.2.0+ */
       ALLOC_OBJ_CLEAR (ks_ssl->ssn, ssl_session);
       ssl_set_session (ks_ssl->ctx, 0, 0, ks_ssl->ssn );
+#endif
       if (ssl_ctx->allowed_ciphers)
        ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers);
+#if POLARSSL_VERSION_NUMBER < 0x01020000
       else
+        /* Handled implicitly in PolarSSL-1.2.0+ */
        ssl_set_ciphersuites (ks_ssl->ctx, default_ciphersuites);
+#endif

       /* Initialise authentication information */
       if (is_server)
        ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx );
 #if defined(ENABLE_PKCS11)
       if (ssl_ctx->priv_key_pkcs11 != NULL)
+#if POLARSSL_VERSION_NUMBER < 0x01020000
        ssl_set_own_cert_pkcs11( ks_ssl->ctx, ssl_ctx->crt_chain,
            ssl_ctx->priv_key_pkcs11 );
+#else
+       ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain,
+           ssl_ctx->priv_key_pkcs11, ssl_pkcs11_decrypt, ssl_pkcs11_sign,
+           ssl_pkcs11_key_len );
+#endif
       else
 #endif
        ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key );

       /* Initialise SSL verification */
       ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED);
+#if POLARSSL_VERSION_NUMBER < 0x01020000
+      ssl_set_verify (ks_ssl->ctx, verify_callback_1_1, session);
+#else
       ssl_set_verify (ks_ssl->ctx, verify_callback, session);
+#endif
       /* TODO: PolarSSL does not currently support sending the CA chain to the 
client */
       ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL );

@@ -543,7 +563,6 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
       ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer);
       ssl_set_bio (ks_ssl->ctx, endless_buf_read, ks_ssl->ct_in,
          endless_buf_write, ks_ssl->ct_out);
-
     }
 }

@@ -556,8 +575,10 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl)
          ssl_free(ks_ssl->ctx);
          free(ks_ssl->ctx);
        }
+#if POLARSSL_VERSION_NUMBER < 0x01020000
       if (ks_ssl->ssn)
        free(ks_ssl->ssn);
+#endif
       if (ks_ssl->ct_in) {
        buf_free_entries(ks_ssl->ct_in);
        free(ks_ssl->ct_in);
@@ -834,7 +855,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct 
buffer *buf,
 void
 print_details (struct key_state_ssl * ks_ssl, const char *prefix)
 {
-  x509_cert *cert;
+  const x509_cert *cert;
   char s1[256];
   char s2[256];

@@ -844,7 +865,11 @@ print_details (struct key_state_ssl * ks_ssl, const char 
*prefix)
                    ssl_get_version (ks_ssl->ctx),
                    ssl_get_ciphersuite(ks_ssl->ctx));

+#if POLARSSL_VERSION_NUMBER < 0x01020000
   cert = ks_ssl->ctx->peer_cert;
+#else
+  cert = ssl_get_peer_cert(ks_ssl->ctx);
+#endif
   if (cert != NULL)
     {
       openvpn_snprintf (s2, sizeof (s2), ", " counter_format " bit RSA", 
(counter_type) cert->rsa.len * 8);
diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_polarssl.h
index 456573f..11edf3e 100644
--- a/src/openvpn/ssl_polarssl.h
+++ b/src/openvpn/ssl_polarssl.h
@@ -30,6 +30,7 @@
 #ifndef SSL_POLARSSL_H_
 #define SSL_POLARSSL_H_

+#include <polarssl/version.h>
 #include <polarssl/ssl.h>

 #if defined(ENABLE_PKCS11)
@@ -73,7 +74,10 @@ struct tls_root_ctx {

 struct key_state_ssl {
         ssl_context *ctx;
+#if POLARSSL_VERSION_NUMBER < 0x01020000
+        /* Implicit in PolarSSL-1.2.0+ */
         ssl_session *ssn;
+#endif
         endless_buffer *ct_in;
         endless_buffer *ct_out;
 };
diff --git a/src/openvpn/ssl_verify_polarssl.c 
b/src/openvpn/ssl_verify_polarssl.c
index 79255cb..86c58d6 100644
--- a/src/openvpn/ssl_verify_polarssl.c
+++ b/src/openvpn/ssl_verify_polarssl.c
@@ -38,17 +38,17 @@
 #if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL)

 #include "ssl_verify.h"
+#include <polarssl/version.h>
 #include <polarssl/sha1.h>

 #define MAX_SUBJECT_LENGTH 256

 int
 verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
-    int preverify_ok)
+    int *flags)
 {
   struct tls_session *session = (struct tls_session *) session_obj;
   struct gc_arena gc = gc_new();
-  int ret = 1;

   ASSERT (cert);
   ASSERT (session);
@@ -59,7 +59,7 @@ verify_callback (void *session_obj, x509_cert *cert, int 
cert_depth,
   cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc));

   /* did peer present cert which was signed by our root cert? */
-  if (!preverify_ok)
+  if (*flags != 0)
     {
       char *subject = x509_get_subject(cert, &gc);

@@ -69,22 +69,47 @@ verify_callback (void *session_obj, x509_cert *cert, int 
cert_depth,
        msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%0x, could not 
extract X509 "
              "subject string from certificate", *flags, cert_depth);

-      goto cleanup;
+      /* Leave flags set to non-zero to indicate that the cert is not ok */
+    }
+  else if (SUCCESS != verify_cert(session, cert, cert_depth))
+    {
+      *flags |= BADCERT_OTHER;
     }

-  if (SUCCESS != verify_cert(session, cert, cert_depth))
-    goto cleanup;
-
-  ret = 0;
-
-cleanup:
   gc_free(&gc);

   /*
-   * PolarSSL expects 1 on failure, 0 on success
+   * PolarSSL-1.2.0+ expects 0 on anything except fatal errors.
    */
-  return ret;
+  return 0;
+}
+
+#if POLARSSL_VERSION_NUMBER < 0x01020000
+int 
+verify_callback_1_1 (void *session_obj, x509_cert *cert, int cert_depth,
+    int preverify_ok)
+{
+    int flags;
+
+    if (preverify_ok)
+           flags = 0;
+    else
+           flags = 0x100 /* BADCERT_OTHER in 1.2 */;
+
+    if (verify_callback(session_obj, cert, cert_depth, &flags) != 0)
+        return 1;
+
+    /*
+     * In PolarSSL-1.2.0+, we should set *flags to nonzero to indicate
+     * verification failure; older PolarSSL expect us to return 1 to indicate
+     * verification failure.
+     */
+    if (flags != 0)
+        return 1;
+
+    return 0;
 }
+#endif

 #ifdef ENABLE_X509ALTUSERNAME
 # warning "X509 alt user name not yet supported for PolarSSL"
diff --git a/src/openvpn/ssl_verify_polarssl.h 
b/src/openvpn/ssl_verify_polarssl.h
index fceee66..21bd6e9 100644
--- a/src/openvpn/ssl_verify_polarssl.h
+++ b/src/openvpn/ssl_verify_polarssl.h
@@ -33,6 +33,7 @@
 #include "syshead.h"
 #include "misc.h"
 #include "manage.h"
+#include <polarssl/version.h>
 #include <polarssl/x509.h>

 #ifndef __OPENVPN_X509_CERT_T_DECLARED
@@ -40,6 +41,10 @@
 typedef x509_cert openvpn_x509_cert_t;
 #endif

+#if POLARSSL_VERSION_NUMBER < 0x01020000
+#define BADCERT_OTHER 0x100
+#endif
+
 /** @name Function for authenticating a new connection from a remote OpenVPN 
peer
  *  @{ */

@@ -55,9 +60,33 @@ typedef x509_cert openvpn_x509_cert_t;
  * calls the PolarSSL library's \c ssl_set_verify_callback() function with \c
  * verify_callback() as its callback argument.
  *
- * It checks preverify_ok, and registers the certificate hash. If these steps
- * succeed, it calls the \c verify_cert() function, which performs
- * OpenVPN-specific verification.
+ * It checks *flags and registers the certificate hash. If these steps succeed,
+ * it calls the \c verify_cert() function, which performs OpenVPN-specific
+ * verification.
+ *
+ * @param session_obj  - The OpenVPN \c tls_session associated with this 
object,
+ *                       as set during SSL session setup.
+ * @param cert         - The certificate used by PolarSSL.
+ * @param cert_depth   - The depth of the current certificate in the chain, 
with
+ *                       0 being the actual certificate.
+ * @param flags        - Whether the remote OpenVPN peer's certificate
+ *                       passed verification.  A value of 0 means it
+ *                       verified successfully, any other value means it
+ *                       failed. \c verify_callback() is considered to have
+ *                       ok'ed this certificate if flags is 0 when it returns.
+ *
+ * @return The return value is 0 unless a fatal error occurred.
+ */
+int verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
+    int *flags);
+
+/** @} name Function for authenticating a new connection from a remote OpenVPN 
peer */
+
+/**
+ * Compatibility shim: verify_callback() for PolarSSL before 1.2.0.
+ * @ingroup control_tls
+ *
+ * As \c verify_callback(), but for use with older versions of PolarSSL.
  *
  * @param session_obj  - The OpenVPN \c tls_session associated with this 
object,
  *                       as set during SSL session setup.
@@ -65,8 +94,8 @@ typedef x509_cert openvpn_x509_cert_t;
  * @param cert_depth   - The depth of the current certificate in the chain, 
with
  *                       0 being the actual certificate.
  * @param preverify_ok - Whether the remote OpenVPN peer's certificate
- *                       past verification.  A value of 1 means it
- *                       verified successfully, 0 means it failed.
+ *                       passed verification.  A value of 1 means it verified
+ *                       successfully, 0 means it failed.
  *
  * @return The return value indicates whether the supplied certificate is
  *     allowed to set up a VPN tunnel.  The following values can be
@@ -74,9 +103,9 @@ typedef x509_cert openvpn_x509_cert_t;
  *      - \c 0: failure, this certificate is not allowed to connect.
  *      - \c 1: success, this certificate is allowed to connect.
  */
-int verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
+#if POLARSSL_VERSION_NUMBER < 0x01020000
+int verify_callback_1_1 (void *session_obj, x509_cert *cert, int cert_depth,
     int preverify_ok);
-
-/** @} name Function for authenticating a new connection from a remote OpenVPN 
peer */
+#endif

 #endif /* SSL_VERIFY_POLARSSL_H_ */
-- 
1.7.9.5


Reply via email to