[arch-commits] Commit in openvpn/repos (8 files)

Christian Hesse eworm at archlinux.org
Sun Jun 18 19:30:56 UTC 2017


    Date: Sunday, June 18, 2017 @ 19:30:55
  Author: eworm
Revision: 298960

archrelease: copy trunk to testing-i686, testing-x86_64

Added:
  openvpn/repos/testing-i686/
  openvpn/repos/testing-i686/0004-openssl-1-1-0.patch
    (from rev 298959, openvpn/trunk/0004-openssl-1-1-0.patch)
  openvpn/repos/testing-i686/PKGBUILD
    (from rev 298959, openvpn/trunk/PKGBUILD)
  openvpn/repos/testing-i686/openvpn.install
    (from rev 298959, openvpn/trunk/openvpn.install)
  openvpn/repos/testing-x86_64/
  openvpn/repos/testing-x86_64/0004-openssl-1-1-0.patch
    (from rev 298959, openvpn/trunk/0004-openssl-1-1-0.patch)
  openvpn/repos/testing-x86_64/PKGBUILD
    (from rev 298959, openvpn/trunk/PKGBUILD)
  openvpn/repos/testing-x86_64/openvpn.install
    (from rev 298959, openvpn/trunk/openvpn.install)

-----------------------------------------+
 testing-i686/0004-openssl-1-1-0.patch   | 1614 ++++++++++++++++++++++++++++++
 testing-i686/PKGBUILD                   |   78 +
 testing-i686/openvpn.install            |   24 
 testing-x86_64/0004-openssl-1-1-0.patch | 1614 ++++++++++++++++++++++++++++++
 testing-x86_64/PKGBUILD                 |   78 +
 testing-x86_64/openvpn.install          |   24 
 6 files changed, 3432 insertions(+)

Copied: openvpn/repos/testing-i686/0004-openssl-1-1-0.patch (from rev 298959, openvpn/trunk/0004-openssl-1-1-0.patch)
===================================================================
--- testing-i686/0004-openssl-1-1-0.patch	                        (rev 0)
+++ testing-i686/0004-openssl-1-1-0.patch	2017-06-18 19:30:55 UTC (rev 298960)
@@ -0,0 +1,1614 @@
+From 17d1ab90c228b1efbe774357bd3265b2af006899 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:23 +0200
+Subject: [PATCH 1/8] OpenSSL: don't use direct access to the internal of
+ X509
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including X509. We have to use the defined
+functions to do so.
+
+In x509_verify_ns_cert_type() in particular, this means that we
+cannot directly check for the extended flags to find whether the
+certificate should be used as a client or as a server certificate.
+We need to leverage the X509_check_purpose() API yet this API is
+far stricter than the currently implemented check. So far, I have
+not been able to find a situation where this stricter test fails
+(although I must admit that I haven't tested that very well).
+
+We double-check the certificate purpose using "direct access" to the
+internal of the certificate object (of course, this is not a real
+direct access, but we still fetch ASN1 strings within the X509 object
+and we check the internal value of these strings). This allow us to
+warn the user if there is a discrepancy between the X509_check_purpose()
+return value and our internal, less strict check.
+
+We use these changes to make peer_cert a non-const parameter to
+x509_verify_ns_cert_type(). The underlying library waits for a
+non-const pointer, and forcing it to be a const pointer does not make
+much sense (please note that this has an effect on the mbedtls part
+too).
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-2-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14792.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                     |  1 +
+ src/openvpn/openssl_compat.h     | 15 +++++++++
+ src/openvpn/ssl_openssl.c        |  3 +-
+ src/openvpn/ssl_verify_backend.h |  2 +-
+ src/openvpn/ssl_verify_mbedtls.c |  2 +-
+ src/openvpn/ssl_verify_openssl.c | 68 ++++++++++++++++++++++++++++++++++------
+ 6 files changed, 78 insertions(+), 13 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 334247df..c30bf3d5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -921,6 +921,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 		[ \
+ 			SSL_CTX_get_default_passwd_cb \
+ 			SSL_CTX_get_default_passwd_cb_userdata \
++			X509_get0_pubkey \
+ 			X509_STORE_get0_objects \
+ 			X509_OBJECT_free \
+ 			X509_OBJECT_get_type \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 811d559c..612bfa56 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -73,6 +73,21 @@ SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
+ }
+ #endif
+ 
++#if !defined(HAVE_X509_GET0_PUBKEY)
++/**
++ * Get the public key from a X509 certificate
++ *
++ * @param x                  X509 certificate
++ * @return                   The certificate public key
++ */
++static inline EVP_PKEY *
++X509_get0_pubkey(const X509 *x)
++{
++    return (x && x->cert_info && x->cert_info->key) ?
++           x->cert_info->key->pkey : NULL;
++}
++#endif
++
+ #if !defined(HAVE_X509_STORE_GET0_OBJECTS)
+ /**
+  * Fetch the X509 object stack from the X509 store
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index 1fa46e18..89c3b014 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -1070,7 +1070,8 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     }
+ 
+     /* get the public key */
+-    ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */
++    EVP_PKEY *pkey = X509_get0_pubkey(cert);
++    ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
+     pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
+ 
+     /* initialize RSA object */
+diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h
+index 35660532..978e54fd 100644
+--- a/src/openvpn/ssl_verify_backend.h
++++ b/src/openvpn/ssl_verify_backend.h
+@@ -210,7 +210,7 @@ void x509_setenv_track(const struct x509_track *xt, struct env_set *es,
+  *                      the expected bit set. \c FAILURE if the certificate does
+  *                      not have NS cert type verification or the wrong bit set.
+  */
+-result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *cert, const int usage);
++result_t x509_verify_ns_cert_type(openvpn_x509_cert_t *cert, const int usage);
+ 
+ /*
+  * Verify X.509 key usage extension field.
+diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c
+index d80b7a53..27c5c3e1 100644
+--- a/src/openvpn/ssl_verify_mbedtls.c
++++ b/src/openvpn/ssl_verify_mbedtls.c
+@@ -410,7 +410,7 @@ x509_setenv(struct env_set *es, int cert_depth, mbedtls_x509_crt *cert)
+ }
+ 
+ result_t
+-x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage)
++x509_verify_ns_cert_type(mbedtls_x509_crt *cert, const int usage)
+ {
+     if (usage == NS_CERT_CHECK_NONE)
+     {
+diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c
+index 5d897b6d..31c16389 100644
+--- a/src/openvpn/ssl_verify_openssl.c
++++ b/src/openvpn/ssl_verify_openssl.c
+@@ -293,18 +293,20 @@ backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc)
+ struct buffer
+ x509_get_sha1_fingerprint(X509 *cert, struct gc_arena *gc)
+ {
+-    struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc);
+-    memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash));
+-    ASSERT(buf_inc_len(&hash, sizeof(cert->sha1_hash)));
++    const EVP_MD *sha1 = EVP_sha1();
++    struct buffer hash = alloc_buf_gc(EVP_MD_size(sha1), gc);
++    X509_digest(cert, EVP_sha1(), BPTR(&hash), NULL);
++    ASSERT(buf_inc_len(&hash, EVP_MD_size(sha1)));
+     return hash;
+ }
+ 
+ struct buffer
+ x509_get_sha256_fingerprint(X509 *cert, struct gc_arena *gc)
+ {
+-    struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc);
++    const EVP_MD *sha256 = EVP_sha256();
++    struct buffer hash = alloc_buf_gc(EVP_MD_size(sha256), gc);
+     X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL);
+-    ASSERT(buf_inc_len(&hash, (EVP_sha256())->md_size));
++    ASSERT(buf_inc_len(&hash, EVP_MD_size(sha256)));
+     return hash;
+ }
+ 
+@@ -569,7 +571,7 @@ x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert)
+ }
+ 
+ result_t
+-x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
++x509_verify_ns_cert_type(openvpn_x509_cert_t *peer_cert, const int usage)
+ {
+     if (usage == NS_CERT_CHECK_NONE)
+     {
+@@ -577,13 +579,59 @@ x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
+     }
+     if (usage == NS_CERT_CHECK_CLIENT)
+     {
+-        return ((peer_cert->ex_flags & EXFLAG_NSCERT)
+-                && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS : FAILURE;
++        /*
++         * Unfortunately, X509_check_purpose() does some weird thing that
++         * prevent it to take a const argument
++         */
++        result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_CLIENT, 0) ?
++	       SUCCESS : FAILURE;
++
++        /*
++         * old versions of OpenSSL allow us to make the less strict check we used to
++         * do. If this less strict check pass, warn user that this might not be the
++         * case when its distribution will update to OpenSSL 1.1
++         */
++        if (result == FAILURE)
++        {
++            ASN1_BIT_STRING *ns;
++            ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL);
++            result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_CLIENT)) ? SUCCESS : FAILURE;
++            if (result == SUCCESS)
++            {
++                msg(M_WARN, "X509: Certificate is a client certificate yet it's purpose "
++                    "cannot be verified (check may fail in the future)");
++            }
++            ASN1_BIT_STRING_free(ns);
++        }
++        return result;
+     }
+     if (usage == NS_CERT_CHECK_SERVER)
+     {
+-        return ((peer_cert->ex_flags & EXFLAG_NSCERT)
+-                && (peer_cert->ex_nscert & NS_SSL_SERVER))  ? SUCCESS : FAILURE;
++        /*
++         * Unfortunately, X509_check_purpose() does some weird thing that
++         * prevent it to take a const argument
++         */
++        result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_SERVER, 0) ?
++	       SUCCESS : FAILURE;
++
++        /*
++         * old versions of OpenSSL allow us to make the less strict check we used to
++         * do. If this less strict check pass, warn user that this might not be the
++         * case when its distribution will update to OpenSSL 1.1
++         */
++        if (result == FAILURE)
++        {
++            ASN1_BIT_STRING *ns;
++            ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL);
++            result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_SERVER)) ? SUCCESS : FAILURE;
++            if (result == SUCCESS)
++            {
++                msg(M_WARN, "X509: Certificate is a server certificate yet it's purpose "
++                    "cannot be verified (check may fail in the future)");
++            }
++            ASN1_BIT_STRING_free(ns);
++        }
++        return result;
+     }
+ 
+     return FAILURE;
+From b8ca5bc3593e539d0735a74b55ed41a792e55033 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:24 +0200
+Subject: [PATCH 2/8] OpenSSL: don't use direct access to the internal of
+ EVP_PKEY
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including EVP_PKEY. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-3-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14795.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  3 +++
+ src/openvpn/openssl_compat.h | 42 ++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl_openssl.c    |  6 +++---
+ 3 files changed, 48 insertions(+), 3 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index c30bf3d5..43f332b2 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -925,6 +925,9 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 			X509_STORE_get0_objects \
+ 			X509_OBJECT_free \
+ 			X509_OBJECT_get_type \
++			EVP_PKEY_id \
++			EVP_PKEY_get0_RSA \
++			EVP_PKEY_get0_DSA \
+ 			RSA_meth_new \
+ 			RSA_meth_free \
+ 			RSA_meth_set_pub_enc \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 612bfa56..60498595 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -133,6 +133,48 @@ X509_OBJECT_get_type(const X509_OBJECT *obj)
+ }
+ #endif
+ 
++#if !defined(HAVE_EVP_PKEY_GET0_RSA)
++/**
++ * Get the RSA object of a public key
++ *
++ * @param pkey                Public key object
++ * @return                    The underlying RSA object
++ */
++static inline RSA *
++EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
++{
++    return pkey ? pkey->pkey.rsa : NULL;
++}
++#endif
++
++#if !defined(HAVE_EVP_PKEY_ID)
++/**
++ * Get the PKEY type
++ *
++ * @param pkey                Public key object
++ * @return                    The key type
++ */
++static inline int
++EVP_PKEY_id(const EVP_PKEY *pkey)
++{
++    return pkey ? pkey->type : EVP_PKEY_NONE;
++}
++#endif
++
++#if !defined(HAVE_EVP_PKEY_GET0_DSA)
++/**
++ * Get the DSA object of a public key
++ *
++ * @param pkey                Public key object
++ * @return                    The underlying DSA object
++ */
++static inline DSA *
++EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
++{
++    return pkey ? pkey->pkey.dsa : NULL;
++}
++#endif
++
+ #if !defined(HAVE_RSA_METH_NEW)
+ /**
+  * Allocate a new RSA method object
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index 89c3b014..c84372d6 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -1072,7 +1072,7 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     /* get the public key */
+     EVP_PKEY *pkey = X509_get0_pubkey(cert);
+     ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
+-    pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
++    pub_rsa = EVP_PKEY_get0_RSA(pkey);
+ 
+     /* initialize RSA object */
+     rsa->n = BN_dup(pub_rsa->n);
+@@ -1677,13 +1677,13 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
+         EVP_PKEY *pkey = X509_get_pubkey(cert);
+         if (pkey != NULL)
+         {
+-            if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL
++            if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL
+                 && pkey->pkey.rsa->n != NULL)
+             {
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                  BN_num_bits(pkey->pkey.rsa->n));
+             }
+-            else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL
++            else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
+                      && pkey->pkey.dsa->p != NULL)
+             {
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
+From f7780af6f1aaffcbbfb8b4dde0f2af052f84b28a Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:25 +0200
+Subject: [PATCH 3/8] OpenSSL: don't use direct access to the internal of RSA
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including RSA. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-4-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14790.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |   4 ++
+ src/openvpn/openssl_compat.h | 100 +++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl_openssl.c    |  24 +++++++----
+ 3 files changed, 119 insertions(+), 9 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 43f332b2..e9ac5a6e 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -928,6 +928,10 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 			EVP_PKEY_id \
+ 			EVP_PKEY_get0_RSA \
+ 			EVP_PKEY_get0_DSA \
++			RSA_set_flags \
++			RSA_bits \
++			RSA_get0_key \
++			RSA_set0_key \
+ 			RSA_meth_new \
+ 			RSA_meth_free \
+ 			RSA_meth_set_pub_enc \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 60498595..e3f20b73 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -175,6 +175,106 @@ EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
+ }
+ #endif
+ 
++#if !defined(HAVE_RSA_SET_FLAGS)
++/**
++ * Set the RSA flags
++ *
++ * @param rsa                 The RSA object
++ * @param flags               New flags value
++ */
++static inline void
++RSA_set_flags(RSA *rsa, int flags)
++{
++    if (rsa)
++    {
++        rsa->flags = flags;
++    }
++}
++#endif
++
++#if !defined(HAVE_RSA_GET0_KEY)
++/**
++ * Get the RSA parameters
++ *
++ * @param rsa                 The RSA object
++ * @param n                   The @c n parameter
++ * @param e                   The @c e parameter
++ * @param d                   The @c d parameter
++ */
++static inline void
++RSA_get0_key(const RSA *rsa, const BIGNUM **n,
++             const BIGNUM **e, const BIGNUM **d)
++{
++    if (n != NULL)
++    {
++        *n = rsa ? rsa->n : NULL;
++    }
++    if (e != NULL)
++    {
++        *e = rsa ? rsa->e : NULL;
++    }
++    if (d != NULL)
++    {
++        *d = rsa ? rsa->d : NULL;
++    }
++}
++#endif
++
++#if !defined(HAVE_RSA_SET0_KEY)
++/**
++ * Set the RSA parameters
++ *
++ * @param rsa                 The RSA object
++ * @param n                   The @c n parameter
++ * @param e                   The @c e parameter
++ * @param d                   The @c d parameter
++ * @return                    1 on success, 0 on error
++ */
++static inline int
++RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
++{
++    if ((rsa->n == NULL && n == NULL)
++        || (rsa->e == NULL && e == NULL))
++    {
++        return 0;
++    }
++
++    if (n != NULL)
++    {
++        BN_free(rsa->n);
++        rsa->n = n;
++    }
++    if (e != NULL)
++    {
++        BN_free(rsa->e);
++        rsa->e = e;
++    }
++    if (d != NULL)
++    {
++        BN_free(rsa->d);
++        rsa->d = d;
++    }
++
++    return 1;
++}
++#endif
++
++#if !defined(HAVE_RSA_BITS)
++/**
++ * Number of significant RSA bits
++ *
++ * @param rsa                The RSA object ; shall not be NULL
++ * @return                   The number of RSA bits or 0 on error
++ */
++static inline int
++RSA_bits(const RSA *rsa)
++{
++    const BIGNUM *n = NULL;
++    RSA_get0_key(rsa, &n, NULL, NULL);
++    return n ? BN_num_bits(n) : 0;
++}
++#endif
++
+ #if !defined(HAVE_RSA_METH_NEW)
+ /**
+  * Allocate a new RSA method object
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index c84372d6..da801ed5 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -973,10 +973,13 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
+ 
+ /* called at RSA_free */
+ static int
+-rsa_finish(RSA *rsa)
++openvpn_extkey_rsa_finish(RSA *rsa)
+ {
+-    RSA_meth_free(rsa->meth);
+-    rsa->meth = NULL;
++    /* meth was allocated in tls_ctx_use_external_private_key() ; since
++     * this function is called when the parent RSA object is destroyed,
++     * it is no longer used after this point so kill it. */
++    const RSA_METHOD *meth = RSA_get_method(rsa);
++    RSA_meth_free((RSA_METHOD *)meth);
+     return 1;
+ }
+ 
+@@ -1058,7 +1061,7 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     RSA_meth_set_priv_enc(rsa_meth, rsa_priv_enc);
+     RSA_meth_set_priv_dec(rsa_meth, rsa_priv_dec);
+     RSA_meth_set_init(rsa_meth, NULL);
+-    RSA_meth_set_finish(rsa_meth, rsa_finish);
++    RSA_meth_set_finish(rsa_meth, openvpn_extkey_rsa_finish);
+     RSA_meth_set0_app_data(rsa_meth, NULL);
+ 
+     /* allocate RSA object */
+@@ -1075,8 +1078,11 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     pub_rsa = EVP_PKEY_get0_RSA(pkey);
+ 
+     /* initialize RSA object */
+-    rsa->n = BN_dup(pub_rsa->n);
+-    rsa->flags |= RSA_FLAG_EXT_PKEY;
++    const BIGNUM *n = NULL;
++    const BIGNUM *e = NULL;
++    RSA_get0_key(pub_rsa, &n, &e, NULL);
++    RSA_set0_key(rsa, BN_dup(n), BN_dup(e), NULL);
++    RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY);
+     if (!RSA_set_method(rsa, rsa_meth))
+     {
+         goto err;
+@@ -1677,11 +1683,11 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
+         EVP_PKEY *pkey = X509_get_pubkey(cert);
+         if (pkey != NULL)
+         {
+-            if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL
+-                && pkey->pkey.rsa->n != NULL)
++            if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL)
+             {
++                RSA *rsa = EVP_PKEY_get0_RSA(pkey);
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+-                                 BN_num_bits(pkey->pkey.rsa->n));
++                                 RSA_bits(rsa));
+             }
+             else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
+                      && pkey->pkey.dsa->p != NULL)
+From c07c0358b553c519ed9d80e2e0a9ba48ca8850e4 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:26 +0200
+Subject: [PATCH 4/8] OpenSSL: don't use direct access to the internal of DSA
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including DSA. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-5-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14791.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  2 ++
+ src/openvpn/openssl_compat.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl_openssl.c    |  6 +++---
+ 3 files changed, 49 insertions(+), 3 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index e9ac5a6e..52348780 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -932,6 +932,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 			RSA_bits \
+ 			RSA_get0_key \
+ 			RSA_set0_key \
++			DSA_get0_pqg \
++			DSA_bits \
+ 			RSA_meth_new \
+ 			RSA_meth_free \
+ 			RSA_meth_set_pub_enc \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index e3f20b73..729fab6c 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -275,6 +275,50 @@ RSA_bits(const RSA *rsa)
+ }
+ #endif
+ 
++#if !defined(HAVE_DSA_GET0_PQG)
++/**
++ * Get the DSA parameters
++ *
++ * @param dsa                 The DSA object
++ * @param p                   The @c p parameter
++ * @param q                   The @c q parameter
++ * @param g                   The @c g parameter
++ */
++static inline void
++DSA_get0_pqg(const DSA *dsa, const BIGNUM **p,
++             const BIGNUM **q, const BIGNUM **g)
++{
++    if (p != NULL)
++    {
++        *p = dsa ? dsa->p : NULL;
++    }
++    if (q != NULL)
++    {
++        *q = dsa ? dsa->q : NULL;
++    }
++    if (g != NULL)
++    {
++        *g = dsa ? dsa->g : NULL;
++    }
++}
++#endif
++
++#if !defined(HAVE_DSA_BITS)
++/**
++ * Number of significant DSA bits
++ *
++ * @param rsa                The DSA object ; shall not be NULL
++ * @return                   The number of DSA bits or 0 on error
++ */
++static inline int
++DSA_bits(const DSA *dsa)
++{
++    const BIGNUM *p = NULL;
++    DSA_get0_pqg(dsa, &p, NULL, NULL);
++    return p ? BN_num_bits(p) : 0;
++}
++#endif
++
+ #if !defined(HAVE_RSA_METH_NEW)
+ /**
+  * Allocate a new RSA method object
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index da801ed5..11f4a567 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -1689,11 +1689,11 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                  RSA_bits(rsa));
+             }
+-            else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
+-                     && pkey->pkey.dsa->p != NULL)
++            else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL)
+             {
++                DSA *dsa = EVP_PKEY_get0_DSA(pkey);
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
+-                                 BN_num_bits(pkey->pkey.dsa->p));
++                                 DSA_bits(dsa));
+             }
+             EVP_PKEY_free(pkey);
+         }
+From 3fd07c31fe8878dc75e760d151d291379c0f8743 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:30 +0200
+Subject: [PATCH 5/8] OpenSSL: force meth->name as non-const when we free()
+ it
+
+We are in control of meth->name (we string_alloc() it in RSA_meth_new())
+so we know that we can free() it when it's no longer needed. Yet we have
+to force the value to be non-const to avoid a compiler warning -- due to
+the fact that OpenSSL defines the value as a const char*, regardless of
+its origin.
+
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-9-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14798.html
+
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ src/openvpn/openssl_compat.h | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 729fab6c..eeacb525 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -349,7 +349,13 @@ RSA_meth_free(RSA_METHOD *meth)
+ {
+     if (meth)
+     {
+-        free(meth->name);
++        /* OpenSSL defines meth->name to be a const pointer, yet we
++         * feed it with an allocated string (from RSA_meth_new()).
++         * Thus we are allowed to free it here. In order to avoid a
++         * "passing 'const char *' to parameter of type 'void *' discards
++         * qualifiers" warning, we force the pointer to be a non-const value.
++         */
++        free((char *)meth->name);
+         free(meth);
+     }
+ }
+From c481ef002803f360743c72727ae3ca971ce59a5d Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:27 +0200
+Subject: [PATCH 6/8] OpenSSL: don't use direct access to the internal of
+ EVP_MD_CTX
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including EVP_MD_CTX. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-6-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14793.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  3 ++
+ src/openvpn/crypto_backend.h | 14 ++++++++
+ src/openvpn/crypto_mbedtls.c | 12 +++++++
+ src/openvpn/crypto_openssl.c | 18 ++++++++--
+ src/openvpn/httpdigest.c     | 78 +++++++++++++++++++++++---------------------
+ src/openvpn/misc.c           | 14 ++++----
+ src/openvpn/openssl_compat.h | 43 ++++++++++++++++++++++++
+ src/openvpn/openvpn.h        |  2 +-
+ src/openvpn/push.c           | 11 ++++---
+ 9 files changed, 143 insertions(+), 52 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 52348780..f971e54a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -919,6 +919,9 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 
+ 	AC_CHECK_FUNCS(
+ 		[ \
++			EVP_MD_CTX_new \
++			EVP_MD_CTX_free \
++			EVP_MD_CTX_reset \
+ 			SSL_CTX_get_default_passwd_cb \
+ 			SSL_CTX_get_default_passwd_cb_userdata \
+ 			X509_get0_pubkey \
+diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
+index e2d2c96f..f1da0432 100644
+--- a/src/openvpn/crypto_backend.h
++++ b/src/openvpn/crypto_backend.h
+@@ -507,6 +507,20 @@ int md_kt_size(const md_kt_t *kt);
+ int md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst);
+ 
+ /*
++ * Allocate a new message digest context
++ *
++ * @return              a new zeroed MD context
++ */
++md_ctx_t *md_ctx_new(void);
++
++/*
++ * Free an existing, non-null message digest context
++ *
++ * @param ctx           Message digest context
++ */
++void md_ctx_free(md_ctx_t *ctx);
++
++/*
+  * Initialises the given message digest context.
+  *
+  * @param ctx           Message digest context
+diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
+index e6388dd5..03cc1308 100644
+--- a/src/openvpn/crypto_mbedtls.c
++++ b/src/openvpn/crypto_mbedtls.c
+@@ -765,6 +765,18 @@ md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
+     return 0 == mbedtls_md(kt, src, src_len, dst);
+ }
+ 
++mbedtls_md_context_t *
++md_ctx_new(void)
++{
++    mbedtls_md_context_t *ctx;
++    ALLOC_OBJ_CLEAR(ctx, mbedtls_md_context_t);
++    return ctx;
++}
++
++void md_ctx_free(mbedtls_md_context_t *ctx)
++{
++    free(ctx);
++}
+ 
+ void
+ md_ctx_init(mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt)
+diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
+index ee20902f..3a5a26f8 100644
+--- a/src/openvpn/crypto_openssl.c
++++ b/src/openvpn/crypto_openssl.c
+@@ -41,6 +41,7 @@
+ #include "integer.h"
+ #include "crypto.h"
+ #include "crypto_backend.h"
++#include "openssl_compat.h"
+ 
+ #include <openssl/des.h>
+ #include <openssl/err.h>
+@@ -843,13 +844,24 @@ md_full(const EVP_MD *kt, const uint8_t *src, int src_len, uint8_t *dst)
+     return EVP_Digest(src, src_len, dst, &in_md_len, kt, NULL);
+ }
+ 
++EVP_MD_CTX *
++md_ctx_new(void)
++{
++    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
++    check_malloc_return(ctx);
++    return ctx;
++}
++
++void md_ctx_free(EVP_MD_CTX *ctx)
++{
++    EVP_MD_CTX_free(ctx);
++}
++
+ void
+ md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt)
+ {
+     ASSERT(NULL != ctx && NULL != kt);
+ 
+-    CLEAR(*ctx);
+-
+     EVP_MD_CTX_init(ctx);
+     EVP_DigestInit(ctx, kt);
+ }
+@@ -857,7 +869,7 @@ md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt)
+ void
+ md_ctx_cleanup(EVP_MD_CTX *ctx)
+ {
+-    EVP_MD_CTX_cleanup(ctx);
++    EVP_MD_CTX_reset(ctx);
+ }
+ 
+ int
+diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c
+index e578c85d..c553f939 100644
+--- a/src/openvpn/httpdigest.c
++++ b/src/openvpn/httpdigest.c
+@@ -80,27 +80,28 @@ DigestCalcHA1(
+     )
+ {
+     HASH HA1;
+-    md_ctx_t md5_ctx;
++    md_ctx_t *md5_ctx = md_ctx_new();
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+ 
+-    md_ctx_init(&md5_ctx, md5_kt);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword));
+-    md_ctx_final(&md5_ctx, HA1);
++    md_ctx_init(md5_ctx, md5_kt);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword));
++    md_ctx_final(md5_ctx, HA1);
+     if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
+     {
+-        md_ctx_init(&md5_ctx, md5_kt);
+-        md_ctx_update(&md5_ctx, HA1, HASHLEN);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
+-        md_ctx_final(&md5_ctx, HA1);
++        md_ctx_init(md5_ctx, md5_kt);
++        md_ctx_update(md5_ctx, HA1, HASHLEN);
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
++        md_ctx_final(md5_ctx, HA1);
+     }
+-    md_ctx_cleanup(&md5_ctx);
++    md_ctx_cleanup(md5_ctx);
++    md_ctx_free(md5_ctx);
+     CvtHex(HA1, SessionKey);
+ }
+ 
+@@ -122,40 +123,41 @@ DigestCalcResponse(
+     HASH RespHash;
+     HASHHEX HA2Hex;
+ 
+-    md_ctx_t md5_ctx;
++    md_ctx_t *md5_ctx = md_ctx_new();
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+ 
+     /* calculate H(A2) */
+-    md_ctx_init(&md5_ctx, md5_kt);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri));
++    md_ctx_init(md5_ctx, md5_kt);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri));
+     if (strcasecmp(pszQop, "auth-int") == 0)
+     {
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN);
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, HEntity, HASHHEXLEN);
+     }
+-    md_ctx_final(&md5_ctx, HA2);
++    md_ctx_final(md5_ctx, HA2);
+     CvtHex(HA2, HA2Hex);
+ 
+     /* calculate response */
+-    md_ctx_init(&md5_ctx, md5_kt);
+-    md_ctx_update(&md5_ctx, HA1, HASHHEXLEN);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_init(md5_ctx, md5_kt);
++    md_ctx_update(md5_ctx, HA1, HASHHEXLEN);
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
+     if (*pszQop)
+     {
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszQop, strlen(pszQop));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszQop, strlen(pszQop));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
+     }
+-    md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN);
+-    md_ctx_final(&md5_ctx, RespHash);
+-    md_ctx_cleanup(&md5_ctx);
++    md_ctx_update(md5_ctx, HA2Hex, HASHHEXLEN);
++    md_ctx_final(md5_ctx, RespHash);
++    md_ctx_cleanup(md5_ctx);
++    md_ctx_free(md5_ctx);
+     CvtHex(RespHash, Response);
+ }
+ 
+diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
+index d286c197..df108b08 100644
+--- a/src/openvpn/misc.c
++++ b/src/openvpn/misc.c
+@@ -1387,7 +1387,7 @@ get_user_pass_auto_userid(struct user_pass *up, const char *tag)
+     static const uint8_t hashprefix[] = "AUTO_USERID_DIGEST";
+ 
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+-    md_ctx_t ctx;
++    md_ctx_t *ctx;
+ 
+     CLEAR(*up);
+     buf_set_write(&buf, (uint8_t *)up->username, USER_PASS_LEN);
+@@ -1395,11 +1395,13 @@ get_user_pass_auto_userid(struct user_pass *up, const char *tag)
+     if (get_default_gateway_mac_addr(macaddr))
+     {
+         dmsg(D_AUTO_USERID, "GUPAU: macaddr=%s", format_hex_ex(macaddr, sizeof(macaddr), 0, 1, ":", &gc));
+-        md_ctx_init(&ctx, md5_kt);
+-        md_ctx_update(&ctx, hashprefix, sizeof(hashprefix) - 1);
+-        md_ctx_update(&ctx, macaddr, sizeof(macaddr));
+-        md_ctx_final(&ctx, digest);
+-        md_ctx_cleanup(&ctx)
++        ctx = md_ctx_new();
++        md_ctx_init(ctx, md5_kt);
++        md_ctx_update(ctx, hashprefix, sizeof(hashprefix) - 1);
++        md_ctx_update(ctx, macaddr, sizeof(macaddr));
++        md_ctx_final(ctx, digest);
++        md_ctx_cleanup(ctx);
++        md_ctx_free(ctx);
+         buf_printf(&buf, "%s", format_hex_ex(digest, sizeof(digest), 0, 256, " ", &gc));
+     }
+     else
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index eeacb525..3d8fad10 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -45,6 +45,49 @@
+ #include <openssl/ssl.h>
+ #include <openssl/x509.h>
+ 
++#if !defined(HAVE_EVP_MD_CTX_RESET)
++/**
++ * Reset a message digest context
++ *
++ * @param ctx                 The message digest context
++ * @return                    1 on success, 0 on error
++ */
++static inline int
++EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
++{
++    EVP_MD_CTX_cleanup(ctx);
++    return 1;
++}
++#endif
++
++#if !defined(HAVE_EVP_MD_CTX_FREE)
++/**
++ * Free an existing message digest context
++ *
++ * @param ctx                 The message digest context
++ */
++static inline void
++EVP_MD_CTX_free(EVP_MD_CTX *ctx)
++{
++    free(ctx);
++}
++#endif
++
++#if !defined(HAVE_EVP_MD_CTX_NEW)
++/**
++ * Allocate a new message digest object
++ *
++ * @return                    A zero'ed message digest object
++ */
++static inline EVP_MD_CTX *
++EVP_MD_CTX_new(void)
++{
++    EVP_MD_CTX *ctx = NULL;
++    ALLOC_OBJ_CLEAR(ctx, EVP_MD_CTX);
++    return ctx;
++}
++#endif
++
+ #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
+ /**
+  * Fetch the default password callback user data from the SSL context
+diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
+index c01e8a2c..9262e68b 100644
+--- a/src/openvpn/openvpn.h
++++ b/src/openvpn/openvpn.h
+@@ -472,7 +472,7 @@ struct context_2
+ 
+     /* hash of pulled options, so we can compare when options change */
+     bool pulled_options_digest_init_done;
+-    md_ctx_t pulled_options_state;
++    md_ctx_t *pulled_options_state;
+     struct sha256_digest pulled_options_digest;
+ 
+     struct event_timeout scheduled_exit;
+diff --git a/src/openvpn/push.c b/src/openvpn/push.c
+index 441d303e..5947a31f 100644
+--- a/src/openvpn/push.c
++++ b/src/openvpn/push.c
+@@ -723,7 +723,8 @@ process_incoming_push_msg(struct context *c,
+             struct buffer buf_orig = buf;
+             if (!c->c2.pulled_options_digest_init_done)
+             {
+-                md_ctx_init(&c->c2.pulled_options_state, md_kt_get("SHA256"));
++                c->c2.pulled_options_state = md_ctx_new();
++                md_ctx_init(c->c2.pulled_options_state, md_kt_get("SHA256"));
+                 c->c2.pulled_options_digest_init_done = true;
+             }
+             if (!c->c2.did_pre_pull_restore)
+@@ -737,14 +738,16 @@ process_incoming_push_msg(struct context *c,
+                                    option_types_found,
+                                    c->c2.es))
+             {
+-                push_update_digest(&c->c2.pulled_options_state, &buf_orig,
++                push_update_digest(c->c2.pulled_options_state, &buf_orig,
+                                    &c->options);
+                 switch (c->options.push_continuation)
+                 {
+                     case 0:
+                     case 1:
+-                        md_ctx_final(&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest);
+-                        md_ctx_cleanup(&c->c2.pulled_options_state);
++                        md_ctx_final(c->c2.pulled_options_state, c->c2.pulled_options_digest.digest);
++                        md_ctx_cleanup(c->c2.pulled_options_state);
++                        md_ctx_free(c->c2.pulled_options_state);
++                        c->c2.pulled_options_state = NULL;
+                         c->c2.pulled_options_digest_init_done = false;
+                         ret = PUSH_MSG_REPLY;
+                         break;
+From 6cbd48a3ead23f004f25943d067fa668efdc580e Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:28 +0200
+Subject: [PATCH 7/8] OpenSSL: don't use direct access to the internal of
+ EVP_CIPHER_CTX
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including EVP_CIPHER_CTX. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-7-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14796.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  2 ++
+ src/openvpn/crypto.c         |  4 ++--
+ src/openvpn/crypto_backend.h | 14 ++++++++++++++
+ src/openvpn/crypto_mbedtls.c | 13 +++++++++++++
+ src/openvpn/crypto_openssl.c | 15 +++++++++++++--
+ src/openvpn/openssl_compat.h | 28 ++++++++++++++++++++++++++++
+ 6 files changed, 72 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index f971e54a..07fc3392 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -919,6 +919,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 
+ 	AC_CHECK_FUNCS(
+ 		[ \
++			EVP_CIPHER_CTX_new \
++			EVP_CIPHER_CTX_free \
+ 			EVP_MD_CTX_new \
+ 			EVP_MD_CTX_free \
+ 			EVP_MD_CTX_reset \
+diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
+index b6d0d550..f7c4d60a 100644
+--- a/src/openvpn/crypto.c
++++ b/src/openvpn/crypto.c
+@@ -829,7 +829,7 @@ init_key_ctx(struct key_ctx *ctx, struct key *key,
+     if (kt->cipher && kt->cipher_length > 0)
+     {
+ 
+-        ALLOC_OBJ(ctx->cipher, cipher_ctx_t);
++        ctx->cipher = cipher_ctx_new();
+         cipher_ctx_init(ctx->cipher, key->cipher, kt->cipher_length,
+                         kt->cipher, enc);
+ 
+@@ -878,7 +878,7 @@ free_key_ctx(struct key_ctx *ctx)
+     if (ctx->cipher)
+     {
+         cipher_ctx_cleanup(ctx->cipher);
+-        free(ctx->cipher);
++        cipher_ctx_free(ctx->cipher);
+         ctx->cipher = NULL;
+     }
+     if (ctx->hmac)
+diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
+index f1da0432..9679ee9b 100644
+--- a/src/openvpn/crypto_backend.h
++++ b/src/openvpn/crypto_backend.h
+@@ -300,6 +300,20 @@ bool cipher_kt_mode_aead(const cipher_kt_t *cipher);
+  */
+ 
+ /**
++ * Allocate a new cipher context
++ *
++ * @return              a new cipher context
++ */
++cipher_ctx_t *cipher_ctx_new(void);
++
++/**
++ * Free a cipher context
++ *
++ * @param ctx           Cipher context.
++ */
++void cipher_ctx_free(cipher_ctx_t *ctx);
++
++/**
+  * Initialise a cipher context, based on the given key and key type.
+  *
+  * @param ctx           Cipher context. May not be NULL
+diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
+index 03cc1308..5f16a1f0 100644
+--- a/src/openvpn/crypto_mbedtls.c
++++ b/src/openvpn/crypto_mbedtls.c
+@@ -508,6 +508,19 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher)
+  *
+  */
+ 
++mbedtls_cipher_context_t *
++cipher_ctx_new(void)
++{
++    mbedtls_cipher_context_t *ctx;
++    ALLOC_OBJ(ctx, mbedtls_cipher_context_t);
++    return ctx;
++}
++
++void
++cipher_ctx_free(mbedtls_cipher_context_t *ctx)
++{
++    free(ctx);
++}
+ 
+ void
+ cipher_ctx_init(mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len,
+diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
+index 3a5a26f8..f4470fc0 100644
+--- a/src/openvpn/crypto_openssl.c
++++ b/src/openvpn/crypto_openssl.c
+@@ -650,6 +650,19 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher)
+  *
+  */
+ 
++cipher_ctx_t *
++cipher_ctx_new(void)
++{
++    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
++    check_malloc_return(ctx);
++    return ctx;
++}
++
++void
++cipher_ctx_free(EVP_CIPHER_CTX *ctx)
++{
++    EVP_CIPHER_CTX_free(ctx);
++}
+ 
+ void
+ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
+@@ -657,8 +670,6 @@ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
+ {
+     ASSERT(NULL != kt && NULL != ctx);
+ 
+-    CLEAR(*ctx);
+-
+     EVP_CIPHER_CTX_init(ctx);
+     if (!EVP_CipherInit(ctx, kt, NULL, NULL, enc))
+     {
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 3d8fad10..c9e2692b 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -88,6 +88,34 @@ EVP_MD_CTX_new(void)
+ }
+ #endif
+ 
++#if !defined(HAVE_EVP_CIPHER_CTX_FREE)
++/**
++ * Free an existing cipher context
++ *
++ * @param ctx                 The cipher context
++ */
++static inline void
++EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c)
++{
++	free(c);
++}
++#endif
++
++#if !defined(HAVE_EVP_CIPHER_CTX_NEW)
++/**
++ * Allocate a new cipher context object
++ *
++ * @return                    A zero'ed cipher context object
++ */
++static inline EVP_CIPHER_CTX *
++EVP_CIPHER_CTX_new(void)
++{
++    EVP_CIPHER_CTX *ctx = NULL;
++    ALLOC_OBJ_CLEAR(ctx, EVP_CIPHER_CTX);
++    return ctx;
++}
++#endif
++
+ #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
+ /**
+  * Fetch the default password callback user data from the SSL context
+From aba98e9050eb54d72d921e70bcd422cb892b9c6c Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:29 +0200
+Subject: [PATCH 8/8] OpenSSL: don't use direct access to the internal of
+ HMAC_CTX
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including HMAC_CTX. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-8-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14797.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  4 +++
+ src/openvpn/crypto.c         |  4 +--
+ src/openvpn/crypto_backend.h | 14 ++++++++++
+ src/openvpn/crypto_mbedtls.c | 15 ++++++++++
+ src/openvpn/crypto_openssl.c | 17 ++++++++++--
+ src/openvpn/ntlm.c           | 12 ++++----
+ src/openvpn/openssl_compat.h | 65 ++++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl.c            | 38 ++++++++++++++------------
+ 8 files changed, 140 insertions(+), 29 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 07fc3392..56ce5f82 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -921,6 +921,10 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 		[ \
+ 			EVP_CIPHER_CTX_new \
+ 			EVP_CIPHER_CTX_free \
++			HMAC_CTX_new \
++			HMAC_CTX_free \
++			HMAC_CTX_reset \
++			HMAC_CTX_init \
+ 			EVP_MD_CTX_new \
+ 			EVP_MD_CTX_free \
+ 			EVP_MD_CTX_reset \
+diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
+index f7c4d60a..191fee8e 100644
+--- a/src/openvpn/crypto.c
++++ b/src/openvpn/crypto.c
+@@ -853,7 +853,7 @@ init_key_ctx(struct key_ctx *ctx, struct key *key,
+     }
+     if (kt->digest && kt->hmac_length > 0)
+     {
+-        ALLOC_OBJ(ctx->hmac, hmac_ctx_t);
++        ctx->hmac = hmac_ctx_new();
+         hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest);
+ 
+         msg(D_HANDSHAKE,
+@@ -884,7 +884,7 @@ free_key_ctx(struct key_ctx *ctx)
+     if (ctx->hmac)
+     {
+         hmac_ctx_cleanup(ctx->hmac);
+-        free(ctx->hmac);
++        hmac_ctx_free(ctx->hmac);
+         ctx->hmac = NULL;
+     }
+     ctx->implicit_iv_len = 0;
+diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
+index 9679ee9b..b7f519b5 100644
+--- a/src/openvpn/crypto_backend.h
++++ b/src/openvpn/crypto_backend.h
+@@ -583,6 +583,20 @@ void md_ctx_final(md_ctx_t *ctx, uint8_t *dst);
+  */
+ 
+ /*
++ * Create a new HMAC context
++ *
++ * @return              A new HMAC context
++ */
++hmac_ctx_t *hmac_ctx_new(void);
++
++/*
++ * Free an existing HMAC context
++ *
++ * @param  ctx           HMAC context to free
++ */
++void hmac_ctx_free(hmac_ctx_t *ctx);
++
++/*
+  * Initialises the given HMAC context, using the given digest
+  * and key.
+  *
+diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
+index 5f16a1f0..24bc3158 100644
+--- a/src/openvpn/crypto_mbedtls.c
++++ b/src/openvpn/crypto_mbedtls.c
+@@ -840,6 +840,21 @@ md_ctx_final(mbedtls_md_context_t *ctx, uint8_t *dst)
+ /*
+  * TODO: re-enable dmsg for crypto debug
+  */
++
++mbedtls_md_context_t *
++hmac_ctx_new(void)
++{
++    mbedtls_md_context_t *ctx;
++    ALLOC_OBJ(ctx, mbedtls_md_context_t);
++    return ctx;
++}
++
++void
++hmac_ctx_free(mbedtls_md_context_t *ctx)
++{
++    free(ctx);
++}
++
+ void
+ hmac_ctx_init(mbedtls_md_context_t *ctx, const uint8_t *key, int key_len,
+               const mbedtls_md_info_t *kt)
+diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
+index f4470fc0..a55e65c1 100644
+--- a/src/openvpn/crypto_openssl.c
++++ b/src/openvpn/crypto_openssl.c
+@@ -910,6 +910,19 @@ md_ctx_final(EVP_MD_CTX *ctx, uint8_t *dst)
+  *
+  */
+ 
++HMAC_CTX *
++hmac_ctx_new(void)
++{
++    HMAC_CTX *ctx = HMAC_CTX_new();
++    check_malloc_return(ctx);
++    return ctx;
++}
++
++void
++hmac_ctx_free(HMAC_CTX *ctx)
++{
++    HMAC_CTX_free(ctx);
++}
+ 
+ void
+ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
+@@ -917,8 +930,6 @@ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
+ {
+     ASSERT(NULL != kt && NULL != ctx);
+ 
+-    CLEAR(*ctx);
+-
+     HMAC_CTX_init(ctx);
+     HMAC_Init_ex(ctx, key, key_len, kt, NULL);
+ 
+@@ -929,7 +940,7 @@ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
+ void
+ hmac_ctx_cleanup(HMAC_CTX *ctx)
+ {
+-    HMAC_CTX_cleanup(ctx);
++    HMAC_CTX_reset(ctx);
+ }
+ 
+ int
+diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c
+index 69b7d426..16d60d2c 100644
+--- a/src/openvpn/ntlm.c
++++ b/src/openvpn/ntlm.c
+@@ -85,13 +85,13 @@ static void
+ gen_hmac_md5(const char *data, int data_len, const char *key, int key_len,char *result)
+ {
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+-    hmac_ctx_t hmac_ctx;
+-    CLEAR(hmac_ctx);
++    hmac_ctx_t *hmac_ctx = hmac_ctx_new();
+ 
+-    hmac_ctx_init(&hmac_ctx, key, key_len, md5_kt);
+-    hmac_ctx_update(&hmac_ctx, (const unsigned char *)data, data_len);
+-    hmac_ctx_final(&hmac_ctx, (unsigned char *)result);
+-    hmac_ctx_cleanup(&hmac_ctx);
++    hmac_ctx_init(hmac_ctx, key, key_len, md5_kt);
++    hmac_ctx_update(hmac_ctx, (const unsigned char *)data, data_len);
++    hmac_ctx_final(hmac_ctx, (unsigned char *)result);
++    hmac_ctx_cleanup(hmac_ctx);
++    hmac_ctx_free(hmac_ctx);
+ }
+ 
+ static void
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index c9e2692b..c765f0bb 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -116,6 +116,71 @@ EVP_CIPHER_CTX_new(void)
+ }
+ #endif
+ 
++#if !defined(HAVE_HMAC_CTX_RESET)
++/**
++ * Reset a HMAC context
++ *
++ * @param ctx                 The HMAC context
++ * @return                    1 on success, 0 on error
++ */
++static inline int
++HMAC_CTX_reset(HMAC_CTX *ctx)
++{
++    HMAC_CTX_cleanup(ctx);
++    return 1;
++}
++#endif
++
++#if !defined(HAVE_HMAC_CTX_INIT)
++/**
++ * Init a HMAC context
++ *
++ * @param ctx                 The HMAC context
++ *
++ * Contrary to many functions in this file, HMAC_CTX_init() is not
++ * an OpenSSL 1.1 function: it comes from previous versions and was
++ * removed in v1.1. As a consequence, there is no distincting in
++ * v1.1 between a cleanup, and init and a reset. Yet, previous OpenSSL
++ * version need this distinction.
++ *
++ * In order to respect previous OpenSSL versions, we implement init
++ * as reset for OpenSSL 1.1+.
++ */
++static inline void
++HMAC_CTX_init(HMAC_CTX *ctx)
++{
++    HMAC_CTX_reset(ctx);
++}
++#endif
++
++#if !defined(HAVE_HMAC_CTX_FREE)
++/**
++ * Free an existing HMAC context
++ *
++ * @param ctx                 The HMAC context
++ */
++static inline void
++HMAC_CTX_free(HMAC_CTX *c)
++{
++	free(c);
++}
++#endif
++
++#if !defined(HAVE_HMAC_CTX_NEW)
++/**
++ * Allocate a new HMAC context object
++ *
++ * @return                    A zero'ed HMAC context object
++ */
++static inline HMAC_CTX *
++HMAC_CTX_new(void)
++{
++    HMAC_CTX *ctx = NULL;
++    ALLOC_OBJ_CLEAR(ctx, HMAC_CTX);
++    return ctx;
++}
++#endif
++
+ #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
+ /**
+  * Fetch the default password callback user data from the SSL context
+diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
+index cc7b1830..c658f377 100644
+--- a/src/openvpn/ssl.c
++++ b/src/openvpn/ssl.c
+@@ -1606,8 +1606,8 @@ tls1_P_hash(const md_kt_t *md_kt,
+ {
+     struct gc_arena gc = gc_new();
+     int chunk;
+-    hmac_ctx_t ctx;
+-    hmac_ctx_t ctx_tmp;
++    hmac_ctx_t *ctx;
++    hmac_ctx_t *ctx_tmp;
+     uint8_t A1[MAX_HMAC_KEY_LENGTH];
+     unsigned int A1_len;
+ 
+@@ -1616,8 +1616,8 @@ tls1_P_hash(const md_kt_t *md_kt,
+     const uint8_t *out_orig = out;
+ #endif
+ 
+-    CLEAR(ctx);
+-    CLEAR(ctx_tmp);
++    ctx = hmac_ctx_new();
++    ctx_tmp = hmac_ctx_new();
+ 
+     dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash sec: %s", format_hex(sec, sec_len, 0, &gc));
+     dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash seed: %s", format_hex(seed, seed_len, 0, &gc));
+@@ -1625,36 +1625,38 @@ tls1_P_hash(const md_kt_t *md_kt,
+     chunk = md_kt_size(md_kt);
+     A1_len = md_kt_size(md_kt);
+ 
+-    hmac_ctx_init(&ctx, sec, sec_len, md_kt);
+-    hmac_ctx_init(&ctx_tmp, sec, sec_len, md_kt);
++    hmac_ctx_init(ctx, sec, sec_len, md_kt);
++    hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt);
+ 
+-    hmac_ctx_update(&ctx,seed,seed_len);
+-    hmac_ctx_final(&ctx, A1);
++    hmac_ctx_update(ctx,seed,seed_len);
++    hmac_ctx_final(ctx, A1);
+ 
+     for (;; )
+     {
+-        hmac_ctx_reset(&ctx);
+-        hmac_ctx_reset(&ctx_tmp);
+-        hmac_ctx_update(&ctx,A1,A1_len);
+-        hmac_ctx_update(&ctx_tmp,A1,A1_len);
+-        hmac_ctx_update(&ctx,seed,seed_len);
++        hmac_ctx_reset(ctx);
++        hmac_ctx_reset(ctx_tmp);
++        hmac_ctx_update(ctx,A1,A1_len);
++        hmac_ctx_update(ctx_tmp,A1,A1_len);
++        hmac_ctx_update(ctx,seed,seed_len);
+ 
+         if (olen > chunk)
+         {
+-            hmac_ctx_final(&ctx, out);
++            hmac_ctx_final(ctx, out);
+             out += chunk;
+             olen -= chunk;
+-            hmac_ctx_final(&ctx_tmp, A1); /* calc the next A1 value */
++            hmac_ctx_final(ctx_tmp, A1); /* calc the next A1 value */
+         }
+         else    /* last one */
+         {
+-            hmac_ctx_final(&ctx, A1);
++            hmac_ctx_final(ctx, A1);
+             memcpy(out,A1,olen);
+             break;
+         }
+     }
+-    hmac_ctx_cleanup(&ctx);
+-    hmac_ctx_cleanup(&ctx_tmp);
++    hmac_ctx_cleanup(ctx);
++    hmac_ctx_free(ctx);
++    hmac_ctx_cleanup(ctx_tmp);
++    hmac_ctx_free(ctx_tmp);
+     secure_memzero(A1, sizeof(A1));
+ 
+     dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex(out_orig, olen_orig, 0, &gc));

Copied: openvpn/repos/testing-i686/PKGBUILD (from rev 298959, openvpn/trunk/PKGBUILD)
===================================================================
--- testing-i686/PKGBUILD	                        (rev 0)
+++ testing-i686/PKGBUILD	2017-06-18 19:30:55 UTC (rev 298960)
@@ -0,0 +1,78 @@
+# $Id$
+# Maintainer: Christian Hesse <mail at eworm.de>
+
+pkgname=openvpn
+pkgver=2.4.2
+pkgrel=2
+pkgdesc='An easy-to-use, robust and highly configurable VPN (Virtual Private Network)'
+arch=('i686' 'x86_64')
+url='http://openvpn.net/index.php/open-source.html'
+depends=('openssl' 'lzo' 'iproute2' 'libsystemd' 'pkcs11-helper')
+optdepends=('easy-rsa: easy CA and certificate handling')
+makedepends=('systemd')
+license=('custom')
+install=openvpn.install
+validpgpkeys=('6D04F8F1B0173111F499795E29584D9F40864578'  # Samuli Seppänen <samuli at openvpn.net>
+              '7ACD56B74144925C6214329757DB9DAB613B8DA1') # David Sommerseth (OpenVPN Technologies, Inc) <davids at openvpn.net>
+source=("https://swupdate.openvpn.net/community/releases/openvpn-${pkgver}.tar.xz"{,.asc}
+        '0004-openssl-1-1-0.patch')
+sha256sums=('df5c4f384b7df6b08a2f6fa8a84b9fd382baf59c2cef1836f82e2a7f62f1bff9'
+            'SKIP'
+            '75259cb14ed8237c2ca5618eca902ed39f720df166e732911e21dd5abcc68b3e')
+
+prepare() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  # allow to build against openssl 1.1.0
+  patch -Np1 < "${srcdir}"/0004-openssl-1-1-0.patch
+
+  # regenerate configure script
+  autoreconf -fi
+}
+
+build() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  ./configure \
+    --prefix=/usr \
+    --sbindir=/usr/bin \
+    --enable-iproute2 \
+    --enable-pkcs11 \
+    --enable-plugins \
+    --enable-systemd \
+    --enable-x509-alt-username
+  make
+}
+
+check() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  make check
+}
+
+package() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  # Install openvpn
+  make DESTDIR="${pkgdir}" install
+
+  # Create empty configuration directories
+  install -d -m0750 -g 90 "${pkgdir}"/etc/openvpn/{client,server}
+
+  # Install examples
+  install -d -m0755 "${pkgdir}"/usr/share/openvpn
+  cp -r sample/sample-config-files "${pkgdir}"/usr/share/openvpn/examples
+
+  # Install license
+  install -d -m0755 "${pkgdir}"/usr/share/licenses/openvpn/
+  ln -sf /usr/share/doc/openvpn/{COPYING,COPYRIGHT.GPL} "${pkgdir}"/usr/share/licenses/openvpn/
+
+  # Install contrib
+  for FILE in $(find contrib -type f); do
+    case "$(file --brief --mime-type "${FILE}")" in
+      "text/x-shellscript") install -D -m0755 "${FILE}" "${pkgdir}/usr/share/openvpn/${FILE}" ;;
+      *) install -D -m0644 "${FILE}" "${pkgdir}/usr/share/openvpn/${FILE}" ;;
+    esac
+  done
+}
+

Copied: openvpn/repos/testing-i686/openvpn.install (from rev 298959, openvpn/trunk/openvpn.install)
===================================================================
--- testing-i686/openvpn.install	                        (rev 0)
+++ testing-i686/openvpn.install	2017-06-18 19:30:55 UTC (rev 298960)
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+post_upgrade() {
+  # return if old package version greater 2.4...
+  (( $(vercmp $2 '2.4') > 0 )) && return
+
+  # upgrade from pre-2.4 version...
+  echo "This upgrade from openvpn $2 to openvpn $1 made changes that require"
+  echo "administrative interaction:"
+  echo " -> Configuration is expected in sub directories now. Move your files"
+  echo "    from /etc/openvpn/ to /etc/openvpn/server/ or /etc/openvpn/client/."
+  echo " -> The plugin lookup path changed, remove extra 'plugins/' from relative paths."
+  echo " -> The systemd unit openvpn at .service was replaced with openvpn-client at .service"
+  echo "    and openvpn-server at .service. Restart and reenable accordingly."
+
+  local UNITS="$(systemctl list-units --quiet --no-pager --no-legend --plain | grep '^openvpn@' | cut -d' ' -f1)"
+  if (( ${#UNITS} )); then
+    echo "This is a (possibly incomplete) list of units that need to be acted on:"
+    for UNIT in ${UNITS}; do
+      echo " -> ${UNIT}"
+    done
+  fi
+}
+

Copied: openvpn/repos/testing-x86_64/0004-openssl-1-1-0.patch (from rev 298959, openvpn/trunk/0004-openssl-1-1-0.patch)
===================================================================
--- testing-x86_64/0004-openssl-1-1-0.patch	                        (rev 0)
+++ testing-x86_64/0004-openssl-1-1-0.patch	2017-06-18 19:30:55 UTC (rev 298960)
@@ -0,0 +1,1614 @@
+From 17d1ab90c228b1efbe774357bd3265b2af006899 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:23 +0200
+Subject: [PATCH 1/8] OpenSSL: don't use direct access to the internal of
+ X509
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including X509. We have to use the defined
+functions to do so.
+
+In x509_verify_ns_cert_type() in particular, this means that we
+cannot directly check for the extended flags to find whether the
+certificate should be used as a client or as a server certificate.
+We need to leverage the X509_check_purpose() API yet this API is
+far stricter than the currently implemented check. So far, I have
+not been able to find a situation where this stricter test fails
+(although I must admit that I haven't tested that very well).
+
+We double-check the certificate purpose using "direct access" to the
+internal of the certificate object (of course, this is not a real
+direct access, but we still fetch ASN1 strings within the X509 object
+and we check the internal value of these strings). This allow us to
+warn the user if there is a discrepancy between the X509_check_purpose()
+return value and our internal, less strict check.
+
+We use these changes to make peer_cert a non-const parameter to
+x509_verify_ns_cert_type(). The underlying library waits for a
+non-const pointer, and forcing it to be a const pointer does not make
+much sense (please note that this has an effect on the mbedtls part
+too).
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-2-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14792.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                     |  1 +
+ src/openvpn/openssl_compat.h     | 15 +++++++++
+ src/openvpn/ssl_openssl.c        |  3 +-
+ src/openvpn/ssl_verify_backend.h |  2 +-
+ src/openvpn/ssl_verify_mbedtls.c |  2 +-
+ src/openvpn/ssl_verify_openssl.c | 68 ++++++++++++++++++++++++++++++++++------
+ 6 files changed, 78 insertions(+), 13 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 334247df..c30bf3d5 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -921,6 +921,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 		[ \
+ 			SSL_CTX_get_default_passwd_cb \
+ 			SSL_CTX_get_default_passwd_cb_userdata \
++			X509_get0_pubkey \
+ 			X509_STORE_get0_objects \
+ 			X509_OBJECT_free \
+ 			X509_OBJECT_get_type \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 811d559c..612bfa56 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -73,6 +73,21 @@ SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
+ }
+ #endif
+ 
++#if !defined(HAVE_X509_GET0_PUBKEY)
++/**
++ * Get the public key from a X509 certificate
++ *
++ * @param x                  X509 certificate
++ * @return                   The certificate public key
++ */
++static inline EVP_PKEY *
++X509_get0_pubkey(const X509 *x)
++{
++    return (x && x->cert_info && x->cert_info->key) ?
++           x->cert_info->key->pkey : NULL;
++}
++#endif
++
+ #if !defined(HAVE_X509_STORE_GET0_OBJECTS)
+ /**
+  * Fetch the X509 object stack from the X509 store
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index 1fa46e18..89c3b014 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -1070,7 +1070,8 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     }
+ 
+     /* get the public key */
+-    ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */
++    EVP_PKEY *pkey = X509_get0_pubkey(cert);
++    ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
+     pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
+ 
+     /* initialize RSA object */
+diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h
+index 35660532..978e54fd 100644
+--- a/src/openvpn/ssl_verify_backend.h
++++ b/src/openvpn/ssl_verify_backend.h
+@@ -210,7 +210,7 @@ void x509_setenv_track(const struct x509_track *xt, struct env_set *es,
+  *                      the expected bit set. \c FAILURE if the certificate does
+  *                      not have NS cert type verification or the wrong bit set.
+  */
+-result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *cert, const int usage);
++result_t x509_verify_ns_cert_type(openvpn_x509_cert_t *cert, const int usage);
+ 
+ /*
+  * Verify X.509 key usage extension field.
+diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c
+index d80b7a53..27c5c3e1 100644
+--- a/src/openvpn/ssl_verify_mbedtls.c
++++ b/src/openvpn/ssl_verify_mbedtls.c
+@@ -410,7 +410,7 @@ x509_setenv(struct env_set *es, int cert_depth, mbedtls_x509_crt *cert)
+ }
+ 
+ result_t
+-x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage)
++x509_verify_ns_cert_type(mbedtls_x509_crt *cert, const int usage)
+ {
+     if (usage == NS_CERT_CHECK_NONE)
+     {
+diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c
+index 5d897b6d..31c16389 100644
+--- a/src/openvpn/ssl_verify_openssl.c
++++ b/src/openvpn/ssl_verify_openssl.c
+@@ -293,18 +293,20 @@ backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc)
+ struct buffer
+ x509_get_sha1_fingerprint(X509 *cert, struct gc_arena *gc)
+ {
+-    struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc);
+-    memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash));
+-    ASSERT(buf_inc_len(&hash, sizeof(cert->sha1_hash)));
++    const EVP_MD *sha1 = EVP_sha1();
++    struct buffer hash = alloc_buf_gc(EVP_MD_size(sha1), gc);
++    X509_digest(cert, EVP_sha1(), BPTR(&hash), NULL);
++    ASSERT(buf_inc_len(&hash, EVP_MD_size(sha1)));
+     return hash;
+ }
+ 
+ struct buffer
+ x509_get_sha256_fingerprint(X509 *cert, struct gc_arena *gc)
+ {
+-    struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc);
++    const EVP_MD *sha256 = EVP_sha256();
++    struct buffer hash = alloc_buf_gc(EVP_MD_size(sha256), gc);
+     X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL);
+-    ASSERT(buf_inc_len(&hash, (EVP_sha256())->md_size));
++    ASSERT(buf_inc_len(&hash, EVP_MD_size(sha256)));
+     return hash;
+ }
+ 
+@@ -569,7 +571,7 @@ x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert)
+ }
+ 
+ result_t
+-x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
++x509_verify_ns_cert_type(openvpn_x509_cert_t *peer_cert, const int usage)
+ {
+     if (usage == NS_CERT_CHECK_NONE)
+     {
+@@ -577,13 +579,59 @@ x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
+     }
+     if (usage == NS_CERT_CHECK_CLIENT)
+     {
+-        return ((peer_cert->ex_flags & EXFLAG_NSCERT)
+-                && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS : FAILURE;
++        /*
++         * Unfortunately, X509_check_purpose() does some weird thing that
++         * prevent it to take a const argument
++         */
++        result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_CLIENT, 0) ?
++	       SUCCESS : FAILURE;
++
++        /*
++         * old versions of OpenSSL allow us to make the less strict check we used to
++         * do. If this less strict check pass, warn user that this might not be the
++         * case when its distribution will update to OpenSSL 1.1
++         */
++        if (result == FAILURE)
++        {
++            ASN1_BIT_STRING *ns;
++            ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL);
++            result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_CLIENT)) ? SUCCESS : FAILURE;
++            if (result == SUCCESS)
++            {
++                msg(M_WARN, "X509: Certificate is a client certificate yet it's purpose "
++                    "cannot be verified (check may fail in the future)");
++            }
++            ASN1_BIT_STRING_free(ns);
++        }
++        return result;
+     }
+     if (usage == NS_CERT_CHECK_SERVER)
+     {
+-        return ((peer_cert->ex_flags & EXFLAG_NSCERT)
+-                && (peer_cert->ex_nscert & NS_SSL_SERVER))  ? SUCCESS : FAILURE;
++        /*
++         * Unfortunately, X509_check_purpose() does some weird thing that
++         * prevent it to take a const argument
++         */
++        result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_SERVER, 0) ?
++	       SUCCESS : FAILURE;
++
++        /*
++         * old versions of OpenSSL allow us to make the less strict check we used to
++         * do. If this less strict check pass, warn user that this might not be the
++         * case when its distribution will update to OpenSSL 1.1
++         */
++        if (result == FAILURE)
++        {
++            ASN1_BIT_STRING *ns;
++            ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL);
++            result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_SERVER)) ? SUCCESS : FAILURE;
++            if (result == SUCCESS)
++            {
++                msg(M_WARN, "X509: Certificate is a server certificate yet it's purpose "
++                    "cannot be verified (check may fail in the future)");
++            }
++            ASN1_BIT_STRING_free(ns);
++        }
++        return result;
+     }
+ 
+     return FAILURE;
+From b8ca5bc3593e539d0735a74b55ed41a792e55033 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:24 +0200
+Subject: [PATCH 2/8] OpenSSL: don't use direct access to the internal of
+ EVP_PKEY
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including EVP_PKEY. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-3-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14795.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  3 +++
+ src/openvpn/openssl_compat.h | 42 ++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl_openssl.c    |  6 +++---
+ 3 files changed, 48 insertions(+), 3 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index c30bf3d5..43f332b2 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -925,6 +925,9 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 			X509_STORE_get0_objects \
+ 			X509_OBJECT_free \
+ 			X509_OBJECT_get_type \
++			EVP_PKEY_id \
++			EVP_PKEY_get0_RSA \
++			EVP_PKEY_get0_DSA \
+ 			RSA_meth_new \
+ 			RSA_meth_free \
+ 			RSA_meth_set_pub_enc \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 612bfa56..60498595 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -133,6 +133,48 @@ X509_OBJECT_get_type(const X509_OBJECT *obj)
+ }
+ #endif
+ 
++#if !defined(HAVE_EVP_PKEY_GET0_RSA)
++/**
++ * Get the RSA object of a public key
++ *
++ * @param pkey                Public key object
++ * @return                    The underlying RSA object
++ */
++static inline RSA *
++EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
++{
++    return pkey ? pkey->pkey.rsa : NULL;
++}
++#endif
++
++#if !defined(HAVE_EVP_PKEY_ID)
++/**
++ * Get the PKEY type
++ *
++ * @param pkey                Public key object
++ * @return                    The key type
++ */
++static inline int
++EVP_PKEY_id(const EVP_PKEY *pkey)
++{
++    return pkey ? pkey->type : EVP_PKEY_NONE;
++}
++#endif
++
++#if !defined(HAVE_EVP_PKEY_GET0_DSA)
++/**
++ * Get the DSA object of a public key
++ *
++ * @param pkey                Public key object
++ * @return                    The underlying DSA object
++ */
++static inline DSA *
++EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
++{
++    return pkey ? pkey->pkey.dsa : NULL;
++}
++#endif
++
+ #if !defined(HAVE_RSA_METH_NEW)
+ /**
+  * Allocate a new RSA method object
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index 89c3b014..c84372d6 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -1072,7 +1072,7 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     /* get the public key */
+     EVP_PKEY *pkey = X509_get0_pubkey(cert);
+     ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */
+-    pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
++    pub_rsa = EVP_PKEY_get0_RSA(pkey);
+ 
+     /* initialize RSA object */
+     rsa->n = BN_dup(pub_rsa->n);
+@@ -1677,13 +1677,13 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
+         EVP_PKEY *pkey = X509_get_pubkey(cert);
+         if (pkey != NULL)
+         {
+-            if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL
++            if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL
+                 && pkey->pkey.rsa->n != NULL)
+             {
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                  BN_num_bits(pkey->pkey.rsa->n));
+             }
+-            else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL
++            else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
+                      && pkey->pkey.dsa->p != NULL)
+             {
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
+From f7780af6f1aaffcbbfb8b4dde0f2af052f84b28a Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:25 +0200
+Subject: [PATCH 3/8] OpenSSL: don't use direct access to the internal of RSA
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including RSA. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-4-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14790.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |   4 ++
+ src/openvpn/openssl_compat.h | 100 +++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl_openssl.c    |  24 +++++++----
+ 3 files changed, 119 insertions(+), 9 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 43f332b2..e9ac5a6e 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -928,6 +928,10 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 			EVP_PKEY_id \
+ 			EVP_PKEY_get0_RSA \
+ 			EVP_PKEY_get0_DSA \
++			RSA_set_flags \
++			RSA_bits \
++			RSA_get0_key \
++			RSA_set0_key \
+ 			RSA_meth_new \
+ 			RSA_meth_free \
+ 			RSA_meth_set_pub_enc \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 60498595..e3f20b73 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -175,6 +175,106 @@ EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
+ }
+ #endif
+ 
++#if !defined(HAVE_RSA_SET_FLAGS)
++/**
++ * Set the RSA flags
++ *
++ * @param rsa                 The RSA object
++ * @param flags               New flags value
++ */
++static inline void
++RSA_set_flags(RSA *rsa, int flags)
++{
++    if (rsa)
++    {
++        rsa->flags = flags;
++    }
++}
++#endif
++
++#if !defined(HAVE_RSA_GET0_KEY)
++/**
++ * Get the RSA parameters
++ *
++ * @param rsa                 The RSA object
++ * @param n                   The @c n parameter
++ * @param e                   The @c e parameter
++ * @param d                   The @c d parameter
++ */
++static inline void
++RSA_get0_key(const RSA *rsa, const BIGNUM **n,
++             const BIGNUM **e, const BIGNUM **d)
++{
++    if (n != NULL)
++    {
++        *n = rsa ? rsa->n : NULL;
++    }
++    if (e != NULL)
++    {
++        *e = rsa ? rsa->e : NULL;
++    }
++    if (d != NULL)
++    {
++        *d = rsa ? rsa->d : NULL;
++    }
++}
++#endif
++
++#if !defined(HAVE_RSA_SET0_KEY)
++/**
++ * Set the RSA parameters
++ *
++ * @param rsa                 The RSA object
++ * @param n                   The @c n parameter
++ * @param e                   The @c e parameter
++ * @param d                   The @c d parameter
++ * @return                    1 on success, 0 on error
++ */
++static inline int
++RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
++{
++    if ((rsa->n == NULL && n == NULL)
++        || (rsa->e == NULL && e == NULL))
++    {
++        return 0;
++    }
++
++    if (n != NULL)
++    {
++        BN_free(rsa->n);
++        rsa->n = n;
++    }
++    if (e != NULL)
++    {
++        BN_free(rsa->e);
++        rsa->e = e;
++    }
++    if (d != NULL)
++    {
++        BN_free(rsa->d);
++        rsa->d = d;
++    }
++
++    return 1;
++}
++#endif
++
++#if !defined(HAVE_RSA_BITS)
++/**
++ * Number of significant RSA bits
++ *
++ * @param rsa                The RSA object ; shall not be NULL
++ * @return                   The number of RSA bits or 0 on error
++ */
++static inline int
++RSA_bits(const RSA *rsa)
++{
++    const BIGNUM *n = NULL;
++    RSA_get0_key(rsa, &n, NULL, NULL);
++    return n ? BN_num_bits(n) : 0;
++}
++#endif
++
+ #if !defined(HAVE_RSA_METH_NEW)
+ /**
+  * Allocate a new RSA method object
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index c84372d6..da801ed5 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -973,10 +973,13 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
+ 
+ /* called at RSA_free */
+ static int
+-rsa_finish(RSA *rsa)
++openvpn_extkey_rsa_finish(RSA *rsa)
+ {
+-    RSA_meth_free(rsa->meth);
+-    rsa->meth = NULL;
++    /* meth was allocated in tls_ctx_use_external_private_key() ; since
++     * this function is called when the parent RSA object is destroyed,
++     * it is no longer used after this point so kill it. */
++    const RSA_METHOD *meth = RSA_get_method(rsa);
++    RSA_meth_free((RSA_METHOD *)meth);
+     return 1;
+ }
+ 
+@@ -1058,7 +1061,7 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     RSA_meth_set_priv_enc(rsa_meth, rsa_priv_enc);
+     RSA_meth_set_priv_dec(rsa_meth, rsa_priv_dec);
+     RSA_meth_set_init(rsa_meth, NULL);
+-    RSA_meth_set_finish(rsa_meth, rsa_finish);
++    RSA_meth_set_finish(rsa_meth, openvpn_extkey_rsa_finish);
+     RSA_meth_set0_app_data(rsa_meth, NULL);
+ 
+     /* allocate RSA object */
+@@ -1075,8 +1078,11 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
+     pub_rsa = EVP_PKEY_get0_RSA(pkey);
+ 
+     /* initialize RSA object */
+-    rsa->n = BN_dup(pub_rsa->n);
+-    rsa->flags |= RSA_FLAG_EXT_PKEY;
++    const BIGNUM *n = NULL;
++    const BIGNUM *e = NULL;
++    RSA_get0_key(pub_rsa, &n, &e, NULL);
++    RSA_set0_key(rsa, BN_dup(n), BN_dup(e), NULL);
++    RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY);
+     if (!RSA_set_method(rsa, rsa_meth))
+     {
+         goto err;
+@@ -1677,11 +1683,11 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
+         EVP_PKEY *pkey = X509_get_pubkey(cert);
+         if (pkey != NULL)
+         {
+-            if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL
+-                && pkey->pkey.rsa->n != NULL)
++            if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL)
+             {
++                RSA *rsa = EVP_PKEY_get0_RSA(pkey);
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+-                                 BN_num_bits(pkey->pkey.rsa->n));
++                                 RSA_bits(rsa));
+             }
+             else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
+                      && pkey->pkey.dsa->p != NULL)
+From c07c0358b553c519ed9d80e2e0a9ba48ca8850e4 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:26 +0200
+Subject: [PATCH 4/8] OpenSSL: don't use direct access to the internal of DSA
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including DSA. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-5-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14791.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  2 ++
+ src/openvpn/openssl_compat.h | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl_openssl.c    |  6 +++---
+ 3 files changed, 49 insertions(+), 3 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index e9ac5a6e..52348780 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -932,6 +932,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 			RSA_bits \
+ 			RSA_get0_key \
+ 			RSA_set0_key \
++			DSA_get0_pqg \
++			DSA_bits \
+ 			RSA_meth_new \
+ 			RSA_meth_free \
+ 			RSA_meth_set_pub_enc \
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index e3f20b73..729fab6c 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -275,6 +275,50 @@ RSA_bits(const RSA *rsa)
+ }
+ #endif
+ 
++#if !defined(HAVE_DSA_GET0_PQG)
++/**
++ * Get the DSA parameters
++ *
++ * @param dsa                 The DSA object
++ * @param p                   The @c p parameter
++ * @param q                   The @c q parameter
++ * @param g                   The @c g parameter
++ */
++static inline void
++DSA_get0_pqg(const DSA *dsa, const BIGNUM **p,
++             const BIGNUM **q, const BIGNUM **g)
++{
++    if (p != NULL)
++    {
++        *p = dsa ? dsa->p : NULL;
++    }
++    if (q != NULL)
++    {
++        *q = dsa ? dsa->q : NULL;
++    }
++    if (g != NULL)
++    {
++        *g = dsa ? dsa->g : NULL;
++    }
++}
++#endif
++
++#if !defined(HAVE_DSA_BITS)
++/**
++ * Number of significant DSA bits
++ *
++ * @param rsa                The DSA object ; shall not be NULL
++ * @return                   The number of DSA bits or 0 on error
++ */
++static inline int
++DSA_bits(const DSA *dsa)
++{
++    const BIGNUM *p = NULL;
++    DSA_get0_pqg(dsa, &p, NULL, NULL);
++    return p ? BN_num_bits(p) : 0;
++}
++#endif
++
+ #if !defined(HAVE_RSA_METH_NEW)
+ /**
+  * Allocate a new RSA method object
+diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
+index da801ed5..11f4a567 100644
+--- a/src/openvpn/ssl_openssl.c
++++ b/src/openvpn/ssl_openssl.c
+@@ -1689,11 +1689,11 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                  RSA_bits(rsa));
+             }
+-            else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
+-                     && pkey->pkey.dsa->p != NULL)
++            else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL)
+             {
++                DSA *dsa = EVP_PKEY_get0_DSA(pkey);
+                 openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
+-                                 BN_num_bits(pkey->pkey.dsa->p));
++                                 DSA_bits(dsa));
+             }
+             EVP_PKEY_free(pkey);
+         }
+From 3fd07c31fe8878dc75e760d151d291379c0f8743 Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:30 +0200
+Subject: [PATCH 5/8] OpenSSL: force meth->name as non-const when we free()
+ it
+
+We are in control of meth->name (we string_alloc() it in RSA_meth_new())
+so we know that we can free() it when it's no longer needed. Yet we have
+to force the value to be non-const to avoid a compiler warning -- due to
+the fact that OpenSSL defines the value as a const char*, regardless of
+its origin.
+
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-9-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14798.html
+
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ src/openvpn/openssl_compat.h | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 729fab6c..eeacb525 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -349,7 +349,13 @@ RSA_meth_free(RSA_METHOD *meth)
+ {
+     if (meth)
+     {
+-        free(meth->name);
++        /* OpenSSL defines meth->name to be a const pointer, yet we
++         * feed it with an allocated string (from RSA_meth_new()).
++         * Thus we are allowed to free it here. In order to avoid a
++         * "passing 'const char *' to parameter of type 'void *' discards
++         * qualifiers" warning, we force the pointer to be a non-const value.
++         */
++        free((char *)meth->name);
+         free(meth);
+     }
+ }
+From c481ef002803f360743c72727ae3ca971ce59a5d Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:27 +0200
+Subject: [PATCH 6/8] OpenSSL: don't use direct access to the internal of
+ EVP_MD_CTX
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including EVP_MD_CTX. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-6-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14793.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  3 ++
+ src/openvpn/crypto_backend.h | 14 ++++++++
+ src/openvpn/crypto_mbedtls.c | 12 +++++++
+ src/openvpn/crypto_openssl.c | 18 ++++++++--
+ src/openvpn/httpdigest.c     | 78 +++++++++++++++++++++++---------------------
+ src/openvpn/misc.c           | 14 ++++----
+ src/openvpn/openssl_compat.h | 43 ++++++++++++++++++++++++
+ src/openvpn/openvpn.h        |  2 +-
+ src/openvpn/push.c           | 11 ++++---
+ 9 files changed, 143 insertions(+), 52 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 52348780..f971e54a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -919,6 +919,9 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 
+ 	AC_CHECK_FUNCS(
+ 		[ \
++			EVP_MD_CTX_new \
++			EVP_MD_CTX_free \
++			EVP_MD_CTX_reset \
+ 			SSL_CTX_get_default_passwd_cb \
+ 			SSL_CTX_get_default_passwd_cb_userdata \
+ 			X509_get0_pubkey \
+diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
+index e2d2c96f..f1da0432 100644
+--- a/src/openvpn/crypto_backend.h
++++ b/src/openvpn/crypto_backend.h
+@@ -507,6 +507,20 @@ int md_kt_size(const md_kt_t *kt);
+ int md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst);
+ 
+ /*
++ * Allocate a new message digest context
++ *
++ * @return              a new zeroed MD context
++ */
++md_ctx_t *md_ctx_new(void);
++
++/*
++ * Free an existing, non-null message digest context
++ *
++ * @param ctx           Message digest context
++ */
++void md_ctx_free(md_ctx_t *ctx);
++
++/*
+  * Initialises the given message digest context.
+  *
+  * @param ctx           Message digest context
+diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
+index e6388dd5..03cc1308 100644
+--- a/src/openvpn/crypto_mbedtls.c
++++ b/src/openvpn/crypto_mbedtls.c
+@@ -765,6 +765,18 @@ md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
+     return 0 == mbedtls_md(kt, src, src_len, dst);
+ }
+ 
++mbedtls_md_context_t *
++md_ctx_new(void)
++{
++    mbedtls_md_context_t *ctx;
++    ALLOC_OBJ_CLEAR(ctx, mbedtls_md_context_t);
++    return ctx;
++}
++
++void md_ctx_free(mbedtls_md_context_t *ctx)
++{
++    free(ctx);
++}
+ 
+ void
+ md_ctx_init(mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt)
+diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
+index ee20902f..3a5a26f8 100644
+--- a/src/openvpn/crypto_openssl.c
++++ b/src/openvpn/crypto_openssl.c
+@@ -41,6 +41,7 @@
+ #include "integer.h"
+ #include "crypto.h"
+ #include "crypto_backend.h"
++#include "openssl_compat.h"
+ 
+ #include <openssl/des.h>
+ #include <openssl/err.h>
+@@ -843,13 +844,24 @@ md_full(const EVP_MD *kt, const uint8_t *src, int src_len, uint8_t *dst)
+     return EVP_Digest(src, src_len, dst, &in_md_len, kt, NULL);
+ }
+ 
++EVP_MD_CTX *
++md_ctx_new(void)
++{
++    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
++    check_malloc_return(ctx);
++    return ctx;
++}
++
++void md_ctx_free(EVP_MD_CTX *ctx)
++{
++    EVP_MD_CTX_free(ctx);
++}
++
+ void
+ md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt)
+ {
+     ASSERT(NULL != ctx && NULL != kt);
+ 
+-    CLEAR(*ctx);
+-
+     EVP_MD_CTX_init(ctx);
+     EVP_DigestInit(ctx, kt);
+ }
+@@ -857,7 +869,7 @@ md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt)
+ void
+ md_ctx_cleanup(EVP_MD_CTX *ctx)
+ {
+-    EVP_MD_CTX_cleanup(ctx);
++    EVP_MD_CTX_reset(ctx);
+ }
+ 
+ int
+diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c
+index e578c85d..c553f939 100644
+--- a/src/openvpn/httpdigest.c
++++ b/src/openvpn/httpdigest.c
+@@ -80,27 +80,28 @@ DigestCalcHA1(
+     )
+ {
+     HASH HA1;
+-    md_ctx_t md5_ctx;
++    md_ctx_t *md5_ctx = md_ctx_new();
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+ 
+-    md_ctx_init(&md5_ctx, md5_kt);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword));
+-    md_ctx_final(&md5_ctx, HA1);
++    md_ctx_init(md5_ctx, md5_kt);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword));
++    md_ctx_final(md5_ctx, HA1);
+     if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
+     {
+-        md_ctx_init(&md5_ctx, md5_kt);
+-        md_ctx_update(&md5_ctx, HA1, HASHLEN);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
+-        md_ctx_final(&md5_ctx, HA1);
++        md_ctx_init(md5_ctx, md5_kt);
++        md_ctx_update(md5_ctx, HA1, HASHLEN);
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
++        md_ctx_final(md5_ctx, HA1);
+     }
+-    md_ctx_cleanup(&md5_ctx);
++    md_ctx_cleanup(md5_ctx);
++    md_ctx_free(md5_ctx);
+     CvtHex(HA1, SessionKey);
+ }
+ 
+@@ -122,40 +123,41 @@ DigestCalcResponse(
+     HASH RespHash;
+     HASHHEX HA2Hex;
+ 
+-    md_ctx_t md5_ctx;
++    md_ctx_t *md5_ctx = md_ctx_new();
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+ 
+     /* calculate H(A2) */
+-    md_ctx_init(&md5_ctx, md5_kt);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri));
++    md_ctx_init(md5_ctx, md5_kt);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri));
+     if (strcasecmp(pszQop, "auth-int") == 0)
+     {
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN);
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, HEntity, HASHHEXLEN);
+     }
+-    md_ctx_final(&md5_ctx, HA2);
++    md_ctx_final(md5_ctx, HA2);
+     CvtHex(HA2, HA2Hex);
+ 
+     /* calculate response */
+-    md_ctx_init(&md5_ctx, md5_kt);
+-    md_ctx_update(&md5_ctx, HA1, HASHHEXLEN);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-    md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
+-    md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_init(md5_ctx, md5_kt);
++    md_ctx_update(md5_ctx, HA1, HASHHEXLEN);
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++    md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
++    md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
+     if (*pszQop)
+     {
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+-        md_ctx_update(&md5_ctx, (const uint8_t *) pszQop, strlen(pszQop));
+-        md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
++        md_ctx_update(md5_ctx, (const uint8_t *) pszQop, strlen(pszQop));
++        md_ctx_update(md5_ctx, (const uint8_t *) ":", 1);
+     }
+-    md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN);
+-    md_ctx_final(&md5_ctx, RespHash);
+-    md_ctx_cleanup(&md5_ctx);
++    md_ctx_update(md5_ctx, HA2Hex, HASHHEXLEN);
++    md_ctx_final(md5_ctx, RespHash);
++    md_ctx_cleanup(md5_ctx);
++    md_ctx_free(md5_ctx);
+     CvtHex(RespHash, Response);
+ }
+ 
+diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
+index d286c197..df108b08 100644
+--- a/src/openvpn/misc.c
++++ b/src/openvpn/misc.c
+@@ -1387,7 +1387,7 @@ get_user_pass_auto_userid(struct user_pass *up, const char *tag)
+     static const uint8_t hashprefix[] = "AUTO_USERID_DIGEST";
+ 
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+-    md_ctx_t ctx;
++    md_ctx_t *ctx;
+ 
+     CLEAR(*up);
+     buf_set_write(&buf, (uint8_t *)up->username, USER_PASS_LEN);
+@@ -1395,11 +1395,13 @@ get_user_pass_auto_userid(struct user_pass *up, const char *tag)
+     if (get_default_gateway_mac_addr(macaddr))
+     {
+         dmsg(D_AUTO_USERID, "GUPAU: macaddr=%s", format_hex_ex(macaddr, sizeof(macaddr), 0, 1, ":", &gc));
+-        md_ctx_init(&ctx, md5_kt);
+-        md_ctx_update(&ctx, hashprefix, sizeof(hashprefix) - 1);
+-        md_ctx_update(&ctx, macaddr, sizeof(macaddr));
+-        md_ctx_final(&ctx, digest);
+-        md_ctx_cleanup(&ctx)
++        ctx = md_ctx_new();
++        md_ctx_init(ctx, md5_kt);
++        md_ctx_update(ctx, hashprefix, sizeof(hashprefix) - 1);
++        md_ctx_update(ctx, macaddr, sizeof(macaddr));
++        md_ctx_final(ctx, digest);
++        md_ctx_cleanup(ctx);
++        md_ctx_free(ctx);
+         buf_printf(&buf, "%s", format_hex_ex(digest, sizeof(digest), 0, 256, " ", &gc));
+     }
+     else
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index eeacb525..3d8fad10 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -45,6 +45,49 @@
+ #include <openssl/ssl.h>
+ #include <openssl/x509.h>
+ 
++#if !defined(HAVE_EVP_MD_CTX_RESET)
++/**
++ * Reset a message digest context
++ *
++ * @param ctx                 The message digest context
++ * @return                    1 on success, 0 on error
++ */
++static inline int
++EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
++{
++    EVP_MD_CTX_cleanup(ctx);
++    return 1;
++}
++#endif
++
++#if !defined(HAVE_EVP_MD_CTX_FREE)
++/**
++ * Free an existing message digest context
++ *
++ * @param ctx                 The message digest context
++ */
++static inline void
++EVP_MD_CTX_free(EVP_MD_CTX *ctx)
++{
++    free(ctx);
++}
++#endif
++
++#if !defined(HAVE_EVP_MD_CTX_NEW)
++/**
++ * Allocate a new message digest object
++ *
++ * @return                    A zero'ed message digest object
++ */
++static inline EVP_MD_CTX *
++EVP_MD_CTX_new(void)
++{
++    EVP_MD_CTX *ctx = NULL;
++    ALLOC_OBJ_CLEAR(ctx, EVP_MD_CTX);
++    return ctx;
++}
++#endif
++
+ #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
+ /**
+  * Fetch the default password callback user data from the SSL context
+diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
+index c01e8a2c..9262e68b 100644
+--- a/src/openvpn/openvpn.h
++++ b/src/openvpn/openvpn.h
+@@ -472,7 +472,7 @@ struct context_2
+ 
+     /* hash of pulled options, so we can compare when options change */
+     bool pulled_options_digest_init_done;
+-    md_ctx_t pulled_options_state;
++    md_ctx_t *pulled_options_state;
+     struct sha256_digest pulled_options_digest;
+ 
+     struct event_timeout scheduled_exit;
+diff --git a/src/openvpn/push.c b/src/openvpn/push.c
+index 441d303e..5947a31f 100644
+--- a/src/openvpn/push.c
++++ b/src/openvpn/push.c
+@@ -723,7 +723,8 @@ process_incoming_push_msg(struct context *c,
+             struct buffer buf_orig = buf;
+             if (!c->c2.pulled_options_digest_init_done)
+             {
+-                md_ctx_init(&c->c2.pulled_options_state, md_kt_get("SHA256"));
++                c->c2.pulled_options_state = md_ctx_new();
++                md_ctx_init(c->c2.pulled_options_state, md_kt_get("SHA256"));
+                 c->c2.pulled_options_digest_init_done = true;
+             }
+             if (!c->c2.did_pre_pull_restore)
+@@ -737,14 +738,16 @@ process_incoming_push_msg(struct context *c,
+                                    option_types_found,
+                                    c->c2.es))
+             {
+-                push_update_digest(&c->c2.pulled_options_state, &buf_orig,
++                push_update_digest(c->c2.pulled_options_state, &buf_orig,
+                                    &c->options);
+                 switch (c->options.push_continuation)
+                 {
+                     case 0:
+                     case 1:
+-                        md_ctx_final(&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest);
+-                        md_ctx_cleanup(&c->c2.pulled_options_state);
++                        md_ctx_final(c->c2.pulled_options_state, c->c2.pulled_options_digest.digest);
++                        md_ctx_cleanup(c->c2.pulled_options_state);
++                        md_ctx_free(c->c2.pulled_options_state);
++                        c->c2.pulled_options_state = NULL;
+                         c->c2.pulled_options_digest_init_done = false;
+                         ret = PUSH_MSG_REPLY;
+                         break;
+From 6cbd48a3ead23f004f25943d067fa668efdc580e Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:28 +0200
+Subject: [PATCH 7/8] OpenSSL: don't use direct access to the internal of
+ EVP_CIPHER_CTX
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including EVP_CIPHER_CTX. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-7-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14796.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  2 ++
+ src/openvpn/crypto.c         |  4 ++--
+ src/openvpn/crypto_backend.h | 14 ++++++++++++++
+ src/openvpn/crypto_mbedtls.c | 13 +++++++++++++
+ src/openvpn/crypto_openssl.c | 15 +++++++++++++--
+ src/openvpn/openssl_compat.h | 28 ++++++++++++++++++++++++++++
+ 6 files changed, 72 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index f971e54a..07fc3392 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -919,6 +919,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 
+ 	AC_CHECK_FUNCS(
+ 		[ \
++			EVP_CIPHER_CTX_new \
++			EVP_CIPHER_CTX_free \
+ 			EVP_MD_CTX_new \
+ 			EVP_MD_CTX_free \
+ 			EVP_MD_CTX_reset \
+diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
+index b6d0d550..f7c4d60a 100644
+--- a/src/openvpn/crypto.c
++++ b/src/openvpn/crypto.c
+@@ -829,7 +829,7 @@ init_key_ctx(struct key_ctx *ctx, struct key *key,
+     if (kt->cipher && kt->cipher_length > 0)
+     {
+ 
+-        ALLOC_OBJ(ctx->cipher, cipher_ctx_t);
++        ctx->cipher = cipher_ctx_new();
+         cipher_ctx_init(ctx->cipher, key->cipher, kt->cipher_length,
+                         kt->cipher, enc);
+ 
+@@ -878,7 +878,7 @@ free_key_ctx(struct key_ctx *ctx)
+     if (ctx->cipher)
+     {
+         cipher_ctx_cleanup(ctx->cipher);
+-        free(ctx->cipher);
++        cipher_ctx_free(ctx->cipher);
+         ctx->cipher = NULL;
+     }
+     if (ctx->hmac)
+diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
+index f1da0432..9679ee9b 100644
+--- a/src/openvpn/crypto_backend.h
++++ b/src/openvpn/crypto_backend.h
+@@ -300,6 +300,20 @@ bool cipher_kt_mode_aead(const cipher_kt_t *cipher);
+  */
+ 
+ /**
++ * Allocate a new cipher context
++ *
++ * @return              a new cipher context
++ */
++cipher_ctx_t *cipher_ctx_new(void);
++
++/**
++ * Free a cipher context
++ *
++ * @param ctx           Cipher context.
++ */
++void cipher_ctx_free(cipher_ctx_t *ctx);
++
++/**
+  * Initialise a cipher context, based on the given key and key type.
+  *
+  * @param ctx           Cipher context. May not be NULL
+diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
+index 03cc1308..5f16a1f0 100644
+--- a/src/openvpn/crypto_mbedtls.c
++++ b/src/openvpn/crypto_mbedtls.c
+@@ -508,6 +508,19 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher)
+  *
+  */
+ 
++mbedtls_cipher_context_t *
++cipher_ctx_new(void)
++{
++    mbedtls_cipher_context_t *ctx;
++    ALLOC_OBJ(ctx, mbedtls_cipher_context_t);
++    return ctx;
++}
++
++void
++cipher_ctx_free(mbedtls_cipher_context_t *ctx)
++{
++    free(ctx);
++}
+ 
+ void
+ cipher_ctx_init(mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len,
+diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
+index 3a5a26f8..f4470fc0 100644
+--- a/src/openvpn/crypto_openssl.c
++++ b/src/openvpn/crypto_openssl.c
+@@ -650,6 +650,19 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher)
+  *
+  */
+ 
++cipher_ctx_t *
++cipher_ctx_new(void)
++{
++    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
++    check_malloc_return(ctx);
++    return ctx;
++}
++
++void
++cipher_ctx_free(EVP_CIPHER_CTX *ctx)
++{
++    EVP_CIPHER_CTX_free(ctx);
++}
+ 
+ void
+ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
+@@ -657,8 +670,6 @@ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
+ {
+     ASSERT(NULL != kt && NULL != ctx);
+ 
+-    CLEAR(*ctx);
+-
+     EVP_CIPHER_CTX_init(ctx);
+     if (!EVP_CipherInit(ctx, kt, NULL, NULL, enc))
+     {
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index 3d8fad10..c9e2692b 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -88,6 +88,34 @@ EVP_MD_CTX_new(void)
+ }
+ #endif
+ 
++#if !defined(HAVE_EVP_CIPHER_CTX_FREE)
++/**
++ * Free an existing cipher context
++ *
++ * @param ctx                 The cipher context
++ */
++static inline void
++EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c)
++{
++	free(c);
++}
++#endif
++
++#if !defined(HAVE_EVP_CIPHER_CTX_NEW)
++/**
++ * Allocate a new cipher context object
++ *
++ * @return                    A zero'ed cipher context object
++ */
++static inline EVP_CIPHER_CTX *
++EVP_CIPHER_CTX_new(void)
++{
++    EVP_CIPHER_CTX *ctx = NULL;
++    ALLOC_OBJ_CLEAR(ctx, EVP_CIPHER_CTX);
++    return ctx;
++}
++#endif
++
+ #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
+ /**
+  * Fetch the default password callback user data from the SSL context
+From aba98e9050eb54d72d921e70bcd422cb892b9c6c Mon Sep 17 00:00:00 2001
+From: Emmanuel Deloget <logout at free.fr>
+Date: Mon, 12 Jun 2017 15:43:29 +0200
+Subject: [PATCH 8/8] OpenSSL: don't use direct access to the internal of
+ HMAC_CTX
+
+OpenSSL 1.1 does not allow us to directly access the internal of
+any data type, including HMAC_CTX. We have to use the defined
+functions to do so.
+
+Compatibility with OpenSSL 1.0 is kept by defining the corresponding
+functions when they are not found in the library.
+
+Signed-off-by: Emmanuel Deloget <logout at free.fr>
+Acked-by: Steffan Karger <steffan.karger at fox-it.com>
+Message-Id: <20170612134330.20971-8-logout at free.fr>
+URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14797.html
+Signed-off-by: Gert Doering <gert at greenie.muc.de>
+---
+ configure.ac                 |  4 +++
+ src/openvpn/crypto.c         |  4 +--
+ src/openvpn/crypto_backend.h | 14 ++++++++++
+ src/openvpn/crypto_mbedtls.c | 15 ++++++++++
+ src/openvpn/crypto_openssl.c | 17 ++++++++++--
+ src/openvpn/ntlm.c           | 12 ++++----
+ src/openvpn/openssl_compat.h | 65 ++++++++++++++++++++++++++++++++++++++++++++
+ src/openvpn/ssl.c            | 38 ++++++++++++++------------
+ 8 files changed, 140 insertions(+), 29 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 07fc3392..56ce5f82 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -921,6 +921,10 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
+ 		[ \
+ 			EVP_CIPHER_CTX_new \
+ 			EVP_CIPHER_CTX_free \
++			HMAC_CTX_new \
++			HMAC_CTX_free \
++			HMAC_CTX_reset \
++			HMAC_CTX_init \
+ 			EVP_MD_CTX_new \
+ 			EVP_MD_CTX_free \
+ 			EVP_MD_CTX_reset \
+diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
+index f7c4d60a..191fee8e 100644
+--- a/src/openvpn/crypto.c
++++ b/src/openvpn/crypto.c
+@@ -853,7 +853,7 @@ init_key_ctx(struct key_ctx *ctx, struct key *key,
+     }
+     if (kt->digest && kt->hmac_length > 0)
+     {
+-        ALLOC_OBJ(ctx->hmac, hmac_ctx_t);
++        ctx->hmac = hmac_ctx_new();
+         hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest);
+ 
+         msg(D_HANDSHAKE,
+@@ -884,7 +884,7 @@ free_key_ctx(struct key_ctx *ctx)
+     if (ctx->hmac)
+     {
+         hmac_ctx_cleanup(ctx->hmac);
+-        free(ctx->hmac);
++        hmac_ctx_free(ctx->hmac);
+         ctx->hmac = NULL;
+     }
+     ctx->implicit_iv_len = 0;
+diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
+index 9679ee9b..b7f519b5 100644
+--- a/src/openvpn/crypto_backend.h
++++ b/src/openvpn/crypto_backend.h
+@@ -583,6 +583,20 @@ void md_ctx_final(md_ctx_t *ctx, uint8_t *dst);
+  */
+ 
+ /*
++ * Create a new HMAC context
++ *
++ * @return              A new HMAC context
++ */
++hmac_ctx_t *hmac_ctx_new(void);
++
++/*
++ * Free an existing HMAC context
++ *
++ * @param  ctx           HMAC context to free
++ */
++void hmac_ctx_free(hmac_ctx_t *ctx);
++
++/*
+  * Initialises the given HMAC context, using the given digest
+  * and key.
+  *
+diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
+index 5f16a1f0..24bc3158 100644
+--- a/src/openvpn/crypto_mbedtls.c
++++ b/src/openvpn/crypto_mbedtls.c
+@@ -840,6 +840,21 @@ md_ctx_final(mbedtls_md_context_t *ctx, uint8_t *dst)
+ /*
+  * TODO: re-enable dmsg for crypto debug
+  */
++
++mbedtls_md_context_t *
++hmac_ctx_new(void)
++{
++    mbedtls_md_context_t *ctx;
++    ALLOC_OBJ(ctx, mbedtls_md_context_t);
++    return ctx;
++}
++
++void
++hmac_ctx_free(mbedtls_md_context_t *ctx)
++{
++    free(ctx);
++}
++
+ void
+ hmac_ctx_init(mbedtls_md_context_t *ctx, const uint8_t *key, int key_len,
+               const mbedtls_md_info_t *kt)
+diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
+index f4470fc0..a55e65c1 100644
+--- a/src/openvpn/crypto_openssl.c
++++ b/src/openvpn/crypto_openssl.c
+@@ -910,6 +910,19 @@ md_ctx_final(EVP_MD_CTX *ctx, uint8_t *dst)
+  *
+  */
+ 
++HMAC_CTX *
++hmac_ctx_new(void)
++{
++    HMAC_CTX *ctx = HMAC_CTX_new();
++    check_malloc_return(ctx);
++    return ctx;
++}
++
++void
++hmac_ctx_free(HMAC_CTX *ctx)
++{
++    HMAC_CTX_free(ctx);
++}
+ 
+ void
+ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
+@@ -917,8 +930,6 @@ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
+ {
+     ASSERT(NULL != kt && NULL != ctx);
+ 
+-    CLEAR(*ctx);
+-
+     HMAC_CTX_init(ctx);
+     HMAC_Init_ex(ctx, key, key_len, kt, NULL);
+ 
+@@ -929,7 +940,7 @@ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len,
+ void
+ hmac_ctx_cleanup(HMAC_CTX *ctx)
+ {
+-    HMAC_CTX_cleanup(ctx);
++    HMAC_CTX_reset(ctx);
+ }
+ 
+ int
+diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c
+index 69b7d426..16d60d2c 100644
+--- a/src/openvpn/ntlm.c
++++ b/src/openvpn/ntlm.c
+@@ -85,13 +85,13 @@ static void
+ gen_hmac_md5(const char *data, int data_len, const char *key, int key_len,char *result)
+ {
+     const md_kt_t *md5_kt = md_kt_get("MD5");
+-    hmac_ctx_t hmac_ctx;
+-    CLEAR(hmac_ctx);
++    hmac_ctx_t *hmac_ctx = hmac_ctx_new();
+ 
+-    hmac_ctx_init(&hmac_ctx, key, key_len, md5_kt);
+-    hmac_ctx_update(&hmac_ctx, (const unsigned char *)data, data_len);
+-    hmac_ctx_final(&hmac_ctx, (unsigned char *)result);
+-    hmac_ctx_cleanup(&hmac_ctx);
++    hmac_ctx_init(hmac_ctx, key, key_len, md5_kt);
++    hmac_ctx_update(hmac_ctx, (const unsigned char *)data, data_len);
++    hmac_ctx_final(hmac_ctx, (unsigned char *)result);
++    hmac_ctx_cleanup(hmac_ctx);
++    hmac_ctx_free(hmac_ctx);
+ }
+ 
+ static void
+diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h
+index c9e2692b..c765f0bb 100644
+--- a/src/openvpn/openssl_compat.h
++++ b/src/openvpn/openssl_compat.h
+@@ -116,6 +116,71 @@ EVP_CIPHER_CTX_new(void)
+ }
+ #endif
+ 
++#if !defined(HAVE_HMAC_CTX_RESET)
++/**
++ * Reset a HMAC context
++ *
++ * @param ctx                 The HMAC context
++ * @return                    1 on success, 0 on error
++ */
++static inline int
++HMAC_CTX_reset(HMAC_CTX *ctx)
++{
++    HMAC_CTX_cleanup(ctx);
++    return 1;
++}
++#endif
++
++#if !defined(HAVE_HMAC_CTX_INIT)
++/**
++ * Init a HMAC context
++ *
++ * @param ctx                 The HMAC context
++ *
++ * Contrary to many functions in this file, HMAC_CTX_init() is not
++ * an OpenSSL 1.1 function: it comes from previous versions and was
++ * removed in v1.1. As a consequence, there is no distincting in
++ * v1.1 between a cleanup, and init and a reset. Yet, previous OpenSSL
++ * version need this distinction.
++ *
++ * In order to respect previous OpenSSL versions, we implement init
++ * as reset for OpenSSL 1.1+.
++ */
++static inline void
++HMAC_CTX_init(HMAC_CTX *ctx)
++{
++    HMAC_CTX_reset(ctx);
++}
++#endif
++
++#if !defined(HAVE_HMAC_CTX_FREE)
++/**
++ * Free an existing HMAC context
++ *
++ * @param ctx                 The HMAC context
++ */
++static inline void
++HMAC_CTX_free(HMAC_CTX *c)
++{
++	free(c);
++}
++#endif
++
++#if !defined(HAVE_HMAC_CTX_NEW)
++/**
++ * Allocate a new HMAC context object
++ *
++ * @return                    A zero'ed HMAC context object
++ */
++static inline HMAC_CTX *
++HMAC_CTX_new(void)
++{
++    HMAC_CTX *ctx = NULL;
++    ALLOC_OBJ_CLEAR(ctx, HMAC_CTX);
++    return ctx;
++}
++#endif
++
+ #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
+ /**
+  * Fetch the default password callback user data from the SSL context
+diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
+index cc7b1830..c658f377 100644
+--- a/src/openvpn/ssl.c
++++ b/src/openvpn/ssl.c
+@@ -1606,8 +1606,8 @@ tls1_P_hash(const md_kt_t *md_kt,
+ {
+     struct gc_arena gc = gc_new();
+     int chunk;
+-    hmac_ctx_t ctx;
+-    hmac_ctx_t ctx_tmp;
++    hmac_ctx_t *ctx;
++    hmac_ctx_t *ctx_tmp;
+     uint8_t A1[MAX_HMAC_KEY_LENGTH];
+     unsigned int A1_len;
+ 
+@@ -1616,8 +1616,8 @@ tls1_P_hash(const md_kt_t *md_kt,
+     const uint8_t *out_orig = out;
+ #endif
+ 
+-    CLEAR(ctx);
+-    CLEAR(ctx_tmp);
++    ctx = hmac_ctx_new();
++    ctx_tmp = hmac_ctx_new();
+ 
+     dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash sec: %s", format_hex(sec, sec_len, 0, &gc));
+     dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash seed: %s", format_hex(seed, seed_len, 0, &gc));
+@@ -1625,36 +1625,38 @@ tls1_P_hash(const md_kt_t *md_kt,
+     chunk = md_kt_size(md_kt);
+     A1_len = md_kt_size(md_kt);
+ 
+-    hmac_ctx_init(&ctx, sec, sec_len, md_kt);
+-    hmac_ctx_init(&ctx_tmp, sec, sec_len, md_kt);
++    hmac_ctx_init(ctx, sec, sec_len, md_kt);
++    hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt);
+ 
+-    hmac_ctx_update(&ctx,seed,seed_len);
+-    hmac_ctx_final(&ctx, A1);
++    hmac_ctx_update(ctx,seed,seed_len);
++    hmac_ctx_final(ctx, A1);
+ 
+     for (;; )
+     {
+-        hmac_ctx_reset(&ctx);
+-        hmac_ctx_reset(&ctx_tmp);
+-        hmac_ctx_update(&ctx,A1,A1_len);
+-        hmac_ctx_update(&ctx_tmp,A1,A1_len);
+-        hmac_ctx_update(&ctx,seed,seed_len);
++        hmac_ctx_reset(ctx);
++        hmac_ctx_reset(ctx_tmp);
++        hmac_ctx_update(ctx,A1,A1_len);
++        hmac_ctx_update(ctx_tmp,A1,A1_len);
++        hmac_ctx_update(ctx,seed,seed_len);
+ 
+         if (olen > chunk)
+         {
+-            hmac_ctx_final(&ctx, out);
++            hmac_ctx_final(ctx, out);
+             out += chunk;
+             olen -= chunk;
+-            hmac_ctx_final(&ctx_tmp, A1); /* calc the next A1 value */
++            hmac_ctx_final(ctx_tmp, A1); /* calc the next A1 value */
+         }
+         else    /* last one */
+         {
+-            hmac_ctx_final(&ctx, A1);
++            hmac_ctx_final(ctx, A1);
+             memcpy(out,A1,olen);
+             break;
+         }
+     }
+-    hmac_ctx_cleanup(&ctx);
+-    hmac_ctx_cleanup(&ctx_tmp);
++    hmac_ctx_cleanup(ctx);
++    hmac_ctx_free(ctx);
++    hmac_ctx_cleanup(ctx_tmp);
++    hmac_ctx_free(ctx_tmp);
+     secure_memzero(A1, sizeof(A1));
+ 
+     dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex(out_orig, olen_orig, 0, &gc));

Copied: openvpn/repos/testing-x86_64/PKGBUILD (from rev 298959, openvpn/trunk/PKGBUILD)
===================================================================
--- testing-x86_64/PKGBUILD	                        (rev 0)
+++ testing-x86_64/PKGBUILD	2017-06-18 19:30:55 UTC (rev 298960)
@@ -0,0 +1,78 @@
+# $Id$
+# Maintainer: Christian Hesse <mail at eworm.de>
+
+pkgname=openvpn
+pkgver=2.4.2
+pkgrel=2
+pkgdesc='An easy-to-use, robust and highly configurable VPN (Virtual Private Network)'
+arch=('i686' 'x86_64')
+url='http://openvpn.net/index.php/open-source.html'
+depends=('openssl' 'lzo' 'iproute2' 'libsystemd' 'pkcs11-helper')
+optdepends=('easy-rsa: easy CA and certificate handling')
+makedepends=('systemd')
+license=('custom')
+install=openvpn.install
+validpgpkeys=('6D04F8F1B0173111F499795E29584D9F40864578'  # Samuli Seppänen <samuli at openvpn.net>
+              '7ACD56B74144925C6214329757DB9DAB613B8DA1') # David Sommerseth (OpenVPN Technologies, Inc) <davids at openvpn.net>
+source=("https://swupdate.openvpn.net/community/releases/openvpn-${pkgver}.tar.xz"{,.asc}
+        '0004-openssl-1-1-0.patch')
+sha256sums=('df5c4f384b7df6b08a2f6fa8a84b9fd382baf59c2cef1836f82e2a7f62f1bff9'
+            'SKIP'
+            '75259cb14ed8237c2ca5618eca902ed39f720df166e732911e21dd5abcc68b3e')
+
+prepare() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  # allow to build against openssl 1.1.0
+  patch -Np1 < "${srcdir}"/0004-openssl-1-1-0.patch
+
+  # regenerate configure script
+  autoreconf -fi
+}
+
+build() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  ./configure \
+    --prefix=/usr \
+    --sbindir=/usr/bin \
+    --enable-iproute2 \
+    --enable-pkcs11 \
+    --enable-plugins \
+    --enable-systemd \
+    --enable-x509-alt-username
+  make
+}
+
+check() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  make check
+}
+
+package() {
+  cd "${srcdir}"/${pkgname}-${pkgver}
+
+  # Install openvpn
+  make DESTDIR="${pkgdir}" install
+
+  # Create empty configuration directories
+  install -d -m0750 -g 90 "${pkgdir}"/etc/openvpn/{client,server}
+
+  # Install examples
+  install -d -m0755 "${pkgdir}"/usr/share/openvpn
+  cp -r sample/sample-config-files "${pkgdir}"/usr/share/openvpn/examples
+
+  # Install license
+  install -d -m0755 "${pkgdir}"/usr/share/licenses/openvpn/
+  ln -sf /usr/share/doc/openvpn/{COPYING,COPYRIGHT.GPL} "${pkgdir}"/usr/share/licenses/openvpn/
+
+  # Install contrib
+  for FILE in $(find contrib -type f); do
+    case "$(file --brief --mime-type "${FILE}")" in
+      "text/x-shellscript") install -D -m0755 "${FILE}" "${pkgdir}/usr/share/openvpn/${FILE}" ;;
+      *) install -D -m0644 "${FILE}" "${pkgdir}/usr/share/openvpn/${FILE}" ;;
+    esac
+  done
+}
+

Copied: openvpn/repos/testing-x86_64/openvpn.install (from rev 298959, openvpn/trunk/openvpn.install)
===================================================================
--- testing-x86_64/openvpn.install	                        (rev 0)
+++ testing-x86_64/openvpn.install	2017-06-18 19:30:55 UTC (rev 298960)
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+post_upgrade() {
+  # return if old package version greater 2.4...
+  (( $(vercmp $2 '2.4') > 0 )) && return
+
+  # upgrade from pre-2.4 version...
+  echo "This upgrade from openvpn $2 to openvpn $1 made changes that require"
+  echo "administrative interaction:"
+  echo " -> Configuration is expected in sub directories now. Move your files"
+  echo "    from /etc/openvpn/ to /etc/openvpn/server/ or /etc/openvpn/client/."
+  echo " -> The plugin lookup path changed, remove extra 'plugins/' from relative paths."
+  echo " -> The systemd unit openvpn at .service was replaced with openvpn-client at .service"
+  echo "    and openvpn-server at .service. Restart and reenable accordingly."
+
+  local UNITS="$(systemctl list-units --quiet --no-pager --no-legend --plain | grep '^openvpn@' | cut -d' ' -f1)"
+  if (( ${#UNITS} )); then
+    echo "This is a (possibly incomplete) list of units that need to be acted on:"
+    for UNIT in ${UNITS}; do
+      echo " -> ${UNIT}"
+    done
+  fi
+}
+



More information about the arch-commits mailing list