Skip to contentSkip to conversation

Add support for OpenSSL 1.1.x

RFC PATCH Superseded [email protected]... 6 participants 92 messages Feb 17, 2017 – Jun 11, 2017

v1 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

cover Add support for OpenSSL 1.1.x

From: Emmanuel Deloget <[email protected]...>

The purpose of this RFC series is to make the latest master of OpenVPN (2.5-git) linkable with OpenSSL v1.1.x. It may not be complete (I may have missed something due to my work environment, but any missing pieces will be added next week) so be a bit cautious with this. The configuration I used (--without-systemd, --without-lzo) seems to work but I must confess I did not tested much.

As you may know, the important information about the API of OpenSSL 1.1 if that it no longer provide access to the content of its objects. The structure types are now opaque and various functions have been added to fetch information from these objects.

Once theses patches have been applied, it is possible to compile OpenSSL with the latest 1.0.1 and with the latest 1.1.0. I still have to check whether compilation with 1.0.0 and 0.9.8 works. I don't try to get the OpenSSL version -- I instead decided to check for the presence of individual functions in the library and chose to reimplement the missing ones. Then I changed caller code in order to use this new interface. The net result is that OpenVPN is now using the OpenSSL 1.1 API -- regardless of the real version of OpenSSL. This might make futur changes simpler at the cost of adding more functions in the openssl_compat.h file.

Las but not least, because of the way I worked I introduced some strange artefacts (I believe they are not really relevant but some of them are weird enough to need some explaination).

* I had to introduce a function of the 1.0 API in the 1.1 code. In the 1.0 API, HMAC_CTX is populated with HMAC_CTX_init() and cleaned with HMAC_CTX_cleanup(). In 1.1 these two functions are gone and replaced with HMAC_CTX_reset(). I decided to use _reset() to implement _cleanup() but since I then could not use it for _init() (that would break an OpenVPN linked with 1.0) I created a small wrapper in 1.1 mode. So, in 1.1, HMAC_CTX_init() calls _reset() -- and everybody is happy (well, maybe not everybody).

* HMAC_CTX, EVP_MD_CTX and a few other objects cannot be allocated using malloc() so I had to change the way these object are used and initialized. I introduces a few new functions in the crypto backend to handle this.

* x509_verify_ns_cert_type() checks had to be changed. OpenSSL 1.1 does not provide any solution to access both X509::ex_flags and X509::ex_nscert so the check could not be implemented this way. The only solution I found was to use X509_check_purpose() but I'm worried that the implemented test is now far more strict.

* weirdly enough, it's no longer possible to duplicate the n parameter of a RSA public key into another RSA public key. If you do so, you also need to duplicate the e parameter. The reason is that you cannot have (n && !e) or (!n && e) (see RSA_set0_key[1]). I deciced to go the same route in my implementation and thus I needed to change the code in tls_ctx_use_external_private_key().

Thanks for your comprehension,

[1] https://github.com/openssl/openssl/blob/master/crypto/rsa/rsa_lib.c#L191

-- Emmanuel Deloget

Emmanuel Deloget (15):
OpenSSL: don't use direct access to the internal of SSL_CTX
OpenSSL: don't use direct access to the internal of X509_STORE
OpenSSL: don't use direct access to the internal of X509_OBJECT
OpenSSL: don't use direct access to the internal of RSA_METHOD
OpenSSL: don't use direct access to the internal of X509
OpenSSL: don't use direct access to the internal of EVP_PKEY
OpenSSL: don't use direct access to the internal of RSA
OpenSSL: don't use direct access to the internal of DSA
OpenSSL: don't use direct access to the internal of X509_STORE_CTX
OpenSSL: don't use direct access to the internal of EVP_MD_CTX
OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX
OpenSSL: don't use direct access to the internal of HMAC_CTX
OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1
OpenSSL: check for the SSL reason, not the full error
OpenSSL: constify getbio() parameters

 configure.ac                     |  37 +++
 src/openvpn/crypto.c             |   8 +-
 src/openvpn/crypto_backend.h     |  42 +++
 src/openvpn/crypto_mbedtls.c     |  40 +++
 src/openvpn/crypto_openssl.c     |  53 +++-
 src/openvpn/httpdigest.c         |  78 ++---
 src/openvpn/misc.c               |  14 +-
 src/openvpn/ntlm.c               |  12 +-
 src/openvpn/openssl_compat.h     | 609 +++++++++++++++++++++++++++++++++++++++
 src/openvpn/openvpn.h            |   2 +-
 src/openvpn/push.c               |  11 +-
 src/openvpn/ssl.c                |  38 +--
 src/openvpn/ssl_openssl.c        |  94 +++---
 src/openvpn/ssl_verify_openssl.c |  55 ++--
 14 files changed, 947 insertions(+), 146 deletions(-)
 create mode 100644 src/openvpn/openssl_compat.h
Signature · 1 line
2.7.4
#1 lore raw

RFC PATCH 1/15 OpenSSL: don't use direct access to the internal of SSL_CTX

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including SSL_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.

---
 configure.ac                 |  9 ++++++
 src/openvpn/openssl_compat.h | 74 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 13 +++++---
 3 files changed, 91 insertions(+), 5 deletions(-)
 create mode 100644 src/openvpn/openssl_compat.h
configure.ac +9 -0
index b29f8b410dfb69bce1145c3bb4a1ba011f0636ec..5fe5d6046ceafa2b577296af772c347ac2ad8039 100644
@@ -898,6 +898,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 		[have_crypto_aead_modes="no"; break]
 	)
 
+	AC_CHECK_FUNCS(
+		[ \
+			SSL_CTX_get_default_passwd_cb \
+			SSL_CTX_get_default_passwd_cb_userdata \
+		],
+		,
+		[]
+	)
+
 	CFLAGS="${saved_CFLAGS}"
 	LIBS="${saved_LIBS}"
 
src/openvpn/openssl_compat.h new file +74 -0

74 lines not on this page · raw message

src/openvpn/ssl_openssl.c +8 -5
index abf69c91a60910e450ae6d2d49ea7e5b1cd3a535..39e92f8cdae52d54d0ad95a9362e4e0e1b2289f4 100644
@@ -45,6 +45,7 @@
 #include "ssl_backend.h"
 #include "ssl_common.h"
 #include "base64.h"
+#include "openssl_compat.h"
 
 #ifdef ENABLE_CRYPTOAPI
 #include "cryptoapi.h"
@@ -658,7 +659,8 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
         {
             for (i = 0; i < sk_X509_num(ca); i++)
             {
-                if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
+                X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx->ctx);
+                if (!X509_STORE_add_cert(cert_store,sk_X509_value(ca, i)))
                 {
                     crypto_msg(M_FATAL,"Cannot add certificate to certificate chain (X509_STORE_add_cert)");
                 }
@@ -760,8 +762,9 @@ tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx,
         goto end;
     }
 
-    x = PEM_read_bio_X509(in, NULL, ctx->ctx->default_passwd_callback,
-                          ctx->ctx->default_passwd_callback_userdata);
+    x = PEM_read_bio_X509(in, NULL,
+                          SSL_CTX_get_default_passwd_cb(ctx->ctx),
+                          SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx));
     if (x == NULL)
     {
         SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB);
@@ -843,8 +846,8 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
     }
 
     pkey = PEM_read_bio_PrivateKey(in, NULL,
-                                   ssl_ctx->default_passwd_callback,
-                                   ssl_ctx->default_passwd_callback_userdata);
+                                   SSL_CTX_get_default_passwd_cb(ctx->ctx),
+                                   SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx));
     if (!pkey)
     {
         goto end;
Signature · 1 line
2.7.4
#2 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 01/15] OpenSSL: don't use direct access to the internal of SSL_CTX

Quoted 153 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including SSL_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.

---
 configure.ac                 |  9 ++++++
 src/openvpn/openssl_compat.h | 74 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 13 +++++---
 3 files changed, 91 insertions(+), 5 deletions(-)
 create mode 100644 src/openvpn/openssl_compat.h
configure.ac +9 -0
index b29f8b410dfb69bce1145c3bb4a1ba011f0636ec..5fe5d6046ceafa2b577296af772c347ac2ad8039 100644
@@ -898,6 +898,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 		[have_crypto_aead_modes="no"; break]
 	)
 
+	AC_CHECK_FUNCS(
+		[ \
+			SSL_CTX_get_default_passwd_cb \
+			SSL_CTX_get_default_passwd_cb_userdata \
+		],
+		,
+		[]
+	)
+
 	CFLAGS="${saved_CFLAGS}"
 	LIBS="${saved_LIBS}"
 
src/openvpn/openssl_compat.h new file +74 -0
new file mode 100644
index 0000000000000000000000000000000000000000..59bad9ff24d10b358419d345181a0e2e52a0c662
@@ -0,0 +1,74 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <[email protected]...>
+ *  Copyright (C) 2010-2017 Fox Crypto B.V. <[email protected]...>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @file OpenSSL compatibility stub
+ *
+ * This file provide compatibility stubs for the OpenSSL libraries
+ * prior to version 1.1. This version introduces many changes in the
+ * library interface, including the fact that various objects and
+ * structures are not fully opaque.
+ */
+
+#ifndef OPENSSL_COMPAT_H_
+#define OPENSSL_COMPAT_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include <openssl/ssl.h>
+
+#if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
+/**
+ * Fetch the default password callback user data from the SSL context
+ *
+ * @param ctx                SSL context
+ * @return                   The password callback user data
+ */
+static inline void *
+SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx)
+{
+    return ctx ? ctx->default_passwd_callback_userdata : NULL;
+}
+#endif
+
+#if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB)
+/**
+ * Fetch the default password callback from the SSL context
+ *
+ * @param ctx                SSL context
+ * @return                   The password callback
+ */
+static inline pem_password_cb *
+SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
+{
+    return ctx ? ctx->default_passwd_callback : NULL;
+}
+#endif
+
+#endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +6 -3
index abf69c91a60910e450ae6d2d49ea7e5b1cd3a535..39e92f8cdae52d54d0ad95a9362e4e0e1b2289f4 100644
@@ -45,6 +45,7 @@
 #include "ssl_backend.h"
 #include "ssl_common.h"
 #include "base64.h"
+#include "openssl_compat.h"
 
 #ifdef ENABLE_CRYPTOAPI
 #include "cryptoapi.h"
@@ -658,7 +659,8 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
         {
             for (i = 0; i < sk_X509_num(ca); i++)
             {
-                if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
+                X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx->ctx);
+                if (!X509_STORE_add_cert(cert_store,sk_X509_value(ca, i)))
                 {
                     crypto_msg(M_FATAL,"Cannot add certificate to certificate chain (X509_STORE_add_cert)");
                 }
@@ -760,8 +762,9 @@ tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx,
         goto end;
     }
 
-    x = PEM_read_bio_X509(in, NULL, ctx->ctx->default_passwd_callback,
-                          ctx->ctx->default_passwd_callback_userdata);
+    x = PEM_read_bio_X509(in, NULL,
+                          SSL_CTX_get_default_passwd_cb(ctx->ctx),
+                          SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx));
     if (x == NULL)
     {
         SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB);

src/openvpn/ssl_openssl.c tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, · line 853

Quoted 10 lines
src/openvpn/ssl_openssl.c +2 -2
@@ -843,8 +846,8 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file,
     }
 
     pkey = PEM_read_bio_PrivateKey(in, NULL,
-                                   ssl_ctx->default_passwd_callback,
-                                   ssl_ctx->default_passwd_callback_userdata);
+                                   SSL_CTX_get_default_passwd_cb(ctx->ctx),
+                                   SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx));
     if (!pkey)
     {
         goto end;

ACK

-Steffan

#3 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of SSL_CTX

In reply to [email protected]...

Your patch has been applied to the master and release/2.4 branch.

commit 6554ac9fed9c5680f22aa4722e6e07ebf3aa3441 (master) commit b936ddfb631e3a4b219bd035f7110da5679b2d12 (release/2.4)

Author: Emmanuel Deloget
Date:   Fri Feb 17 23:00:40 2017 +0100
     OpenSSL: don't use direct access to the internal of SSL_CTX

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <a77187a66affdba318ef70e0e218b69cdad509d1.1487368114.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14088.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#4 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 01/15] OpenSSL: don't use direct access to the internal of SSL_CTX

In reply to [email protected]...

Good morning,

Quoted 6 lines · On Fri, Feb 17, 2017 at 11:00:40PM +0100, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including SSL_CTX. We have to use the defined functions to do so.

Quoted 7 lines

Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library.

---
 configure.ac                 |  9 ++++++
 src/openvpn/openssl_compat.h | 74 ++++++++++++++++++++++++++++++++++++++++++++

This patch brings two problems outside the "OpenSSL functionality" part.

- openssl_compat.h is not included in the built tarballs, so mingw builds fail (and "builds for anyone building from tarballs" would break) -> findable by running "make distcheck"

- configure.ac does something to CentOS 6 / RHEL 6 which makes configure explode:

...
checking for linux/if_tun.h... yes
checking tap-windows.h usability... no
checking tap-windows.h presence... no
checking for tap-windows.h... no
checking whether TUNSETPERSIST is declared... yes checking for setcon in -lselinux... yes
checking for pam_start in -lpam... yes
checking for PKCS11_HELPER... no
./configure: line 21440: syntax error near unexpected token fi' ./configure: line 21440: fi'

The first one is easily fixed, but I do not know how to tackle the second one - no access to a CentOS6/RHEL6 box, and not enough autoconf clue to see this right away. Patch *looks* good... most likely just a stray "\" where none should be, or so...

Please :-)

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#5 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 01/15] OpenSSL: don't use direct access to the internal of SSL_CTX

Hi,

Quoted 6 lines · Gert Doering

This patch brings two problems outside the "OpenSSL functionality" part.

- openssl_compat.h is not included in the built tarballs, so mingw builds fail (and "builds for anyone building from tarballs" would break) -> findable by running "make distcheck"

This has been fixed & pushed (so we can build windows snapshots again).

Quoted 14 lines

- configure.ac does something to CentOS 6 / RHEL 6 which makes configure explode:

...
checking for linux/if_tun.h... yes
checking tap-windows.h usability... no
checking tap-windows.h presence... no
checking for tap-windows.h... no
checking whether TUNSETPERSIST is declared... yes checking for setcon in -lselinux... yes
checking for pam_start in -lpam... yes
checking for PKCS11_HELPER... no
./configure: line 21440: syntax error near unexpected token fi' ./configure: line 21440: fi'

This still needs investigation.

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#6 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 01/15] OpenSSL: don't use direct access to the internal of SSL_CTX

Hello,

Quoted 27 lines · Gert Doering

Hi,

Quoted 6 lines · Gert Doering

This patch brings two problems outside the "OpenSSL functionality" part.

- openssl_compat.h is not included in the built tarballs, so mingw builds fail (and "builds for anyone building from tarballs" would break) -> findable by running "make distcheck"

This has been fixed & pushed (so we can build windows snapshots again).

Quoted 14 lines

- configure.ac does something to CentOS 6 / RHEL 6 which makes configure explode:

...
checking for linux/if_tun.h... yes
checking tap-windows.h usability... no
checking tap-windows.h presence... no
checking for tap-windows.h... no
checking whether TUNSETPERSIST is declared... yes checking for setcon in -lselinux... yes
checking for pam_start in -lpam... yes
checking for PKCS11_HELPER... no
./configure: line 21440: syntax error near unexpected token fi' ./configure: line 21440: fi'

Quoted 1 line

This still needs investigation.

I'm taking the time to install a CentOS 6 on a VM. I'll test this asap.

Best regards,

-- Emmanuel Deloget

#7 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 01/15] OpenSSL: don't use direct access to the internal of SSL_CTX

Quoted 15 lines · Emmanuel Deloget
Quoted 15 lines
Quoted 14 lines

- configure.ac does something to CentOS 6 / RHEL 6 which makes configure explode:

...
checking for linux/if_tun.h... yes
checking tap-windows.h usability... no
checking tap-windows.h presence... no
checking for tap-windows.h... no
checking whether TUNSETPERSIST is declared... yes checking for setcon in -lselinux... yes
checking for pam_start in -lpam... yes
checking for PKCS11_HELPER... no
./configure: line 21440: syntax error near unexpected token fi' ./configure: line 21440: fi'

Quoted 3 lines
Quoted 1 line

This still needs investigation.

I'm taking the time to install a CentOS 6 on a VM. I'll test this asap.

I have a fix ready, but am busy with testing it on various platforms.

-Steffan

#8 lore raw

PATCH 1/1 OpenSSL: 1.1 fallout - fix configure on old autoconf

In reply to Gert Doering

Older versions of autoconf generate an empty "else fi" block for empty fields in an AC_CHECK_FUNCS() macro. This breaks on e.g. RHEL6.

---
 configure.ac | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
configure.ac +1 -3
index 546a7d6..79ef52d 100644
@@ -912,9 +912,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			X509_STORE_get0_objects \
 			X509_OBJECT_free \
 			X509_OBJECT_get_type \
-		],
-		,
-		[]
+		]
 	)
 
 	CFLAGS="${saved_CFLAGS}"
Signature · 1 line
2.7.4
#9 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: 1.1 fallout - fix configure on old autoconf

ACK, thanks.

Your patch has been applied to the master and release/2.4 branch.

commit 07372a0fdeb3638204d197d0614f776a0eb73ab9 (master) commit b97a5cc044dc6db3f0e1f9f06a6f5da522f0a33a (release/2.4)

Author: Steffan Karger
Date:   Thu Feb 23 11:35:38 2017 +0100
     OpenSSL: 1.1 fallout - fix configure on old autoconf

     Signed-off-by: Steffan Karger <[email protected]...>
     Acked-by: Gert Doering <[email protected]...>
     Message-Id: <[email protected]...>
     URL: http://www.mail-archive.com/search?l=mid&[email protected]...
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#10 lore raw

RFC PATCH 2/15 OpenSSL: don't use direct access to the internal of X509_STORE

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_STORE. 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.

---
 configure.ac                     |  1 +
 src/openvpn/openssl_compat.h     | 15 +++++++++++++++
 src/openvpn/ssl_openssl.c        |  7 ++++---
 src/openvpn/ssl_verify_openssl.c |  6 ++++--
 4 files changed, 24 insertions(+), 5 deletions(-)
configure.ac +1 -0
index 5fe5d6046ceafa2b577296af772c347ac2ad8039..415128c9f8687a53e4a73419f3048d07f66b70cc 100644
@@ -902,6 +902,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_STORE_get0_objects \
 		],
 		,
 		[]
src/openvpn/openssl_compat.h +15 -0
index 59bad9ff24d10b358419d345181a0e2e52a0c662..016008bc1705a41ee0ee09fecfc0b16b282cede3 100644
@@ -42,6 +42,7 @@
 #endif
 
 #include <openssl/ssl.h>
+#include <openssl/x509.h>
 
 #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
 /**
@@ -71,4 +72,18 @@ SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
 }
 #endif
 
+#if !defined(HAVE_X509_STORE_GET0_OBJECTS)
+/**
+ * Fetch the X509 object stack from the X509 store
+ *
+ * @param store              X509 object store
+ * @return                   the X509 object stack
+ */
+static inline STACK_OF(X509_OBJECT) *
+X509_STORE_get0_objects(X509_STORE *store)
+{
+    return store ? store->objs : NULL;
+}
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +4 -3
index 39e92f8cdae52d54d0ad95a9362e4e0e1b2289f4..e57de43a748c89ff58ea00abade0b1c317013258 100644
@@ -900,13 +900,14 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
     /* Always start with a cleared CRL list, for that we
      * we need to manually find the CRL object from the stack
      * and remove it */
-    for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
+    STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
+    for (int i = 0; i < sk_X509_OBJECT_num(objs); i++)
     {
-        X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i);
+        X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
         if (obj->type == X509_LU_CRL)
         {
-            sk_X509_OBJECT_delete(store->objs, i);
+            sk_X509_OBJECT_delete(objs, i);
             X509_OBJECT_free_contents(obj);
             OPENSSL_free(obj);
         }
src/openvpn/ssl_verify_openssl.c +4 -2
index 274e2bbf96b6c943ce628eab143f8c76e1c47103..fabbb0c370b123f54ce4a1eaf5f9650b440f47f8 100644
@@ -43,6 +43,7 @@
 #include "ssl_openssl.h"
 #include "ssl_verify.h"
 #include "ssl_verify_backend.h"
+#include "openssl_compat.h"
 
 #include <openssl/x509v3.h>
 #include <openssl/err.h>
@@ -715,9 +716,10 @@ tls_verify_crl_missing(const struct tls_options *opt)
         crypto_msg(M_FATAL, "Cannot get certificate store");
     }
 
-    for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
+    STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
+    for (int i = 0; i < sk_X509_OBJECT_num(objs); i++)
     {
-        X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i);
+        X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
         if (obj->type == X509_LU_CRL)
         {
Signature · 1 line
2.7.4
#11 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 02/15] OpenSSL: don't use direct access to the internal of X509_STORE

Quoted 98 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_STORE. 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.

---
 configure.ac                     |  1 +
 src/openvpn/openssl_compat.h     | 15 +++++++++++++++
 src/openvpn/ssl_openssl.c        |  7 ++++---
 src/openvpn/ssl_verify_openssl.c |  6 ++++--
 4 files changed, 24 insertions(+), 5 deletions(-)
configure.ac +1 -0
index 5fe5d6046ceafa2b577296af772c347ac2ad8039..415128c9f8687a53e4a73419f3048d07f66b70cc 100644
@@ -902,6 +902,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_STORE_get0_objects \
 		],
 		,
 		[]
src/openvpn/openssl_compat.h +15 -0
index 59bad9ff24d10b358419d345181a0e2e52a0c662..016008bc1705a41ee0ee09fecfc0b16b282cede3 100644
@@ -42,6 +42,7 @@
 #endif
 
 #include <openssl/ssl.h>
+#include <openssl/x509.h>
 
 #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
 /**
@@ -71,4 +72,18 @@ SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
 }
 #endif
 
+#if !defined(HAVE_X509_STORE_GET0_OBJECTS)
+/**
+ * Fetch the X509 object stack from the X509 store
+ *
+ * @param store              X509 object store
+ * @return                   the X509 object stack
+ */
+static inline STACK_OF(X509_OBJECT) *
+X509_STORE_get0_objects(X509_STORE *store)
+{
+    return store ? store->objs : NULL;
+}
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +4 -3
index 39e92f8cdae52d54d0ad95a9362e4e0e1b2289f4..e57de43a748c89ff58ea00abade0b1c317013258 100644
@@ -900,13 +900,14 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
     /* Always start with a cleared CRL list, for that we
      * we need to manually find the CRL object from the stack
      * and remove it */
-    for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
+    STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
+    for (int i = 0; i < sk_X509_OBJECT_num(objs); i++)
     {
-        X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i);
+        X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
         if (obj->type == X509_LU_CRL)
         {
-            sk_X509_OBJECT_delete(store->objs, i);
+            sk_X509_OBJECT_delete(objs, i);
             X509_OBJECT_free_contents(obj);
             OPENSSL_free(obj);
         }
src/openvpn/ssl_verify_openssl.c +1 -0
index 274e2bbf96b6c943ce628eab143f8c76e1c47103..fabbb0c370b123f54ce4a1eaf5f9650b440f47f8 100644
@@ -43,6 +43,7 @@
 #include "ssl_openssl.h"
 #include "ssl_verify.h"
 #include "ssl_verify_backend.h"
+#include "openssl_compat.h"
 
 #include <openssl/x509v3.h>
 #include <openssl/err.h>
@@ -715,9 +716,10 @@ tls_verify_crl_missing(const struct tls_options *opt)
         crypto_msg(M_FATAL, "Cannot get certificate store");
     }

src/openvpn/ssl_verify_openssl.c tls_verify_crl_missing(const struct tls_options *opt) · line 725

Quoted 10 lines
src/openvpn/ssl_verify_openssl.c +3 -2
 
-    for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
+    STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store);
+    for (int i = 0; i < sk_X509_OBJECT_num(objs); i++)
     {
-        X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i);
+        X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
         if (obj->type == X509_LU_CRL)
         {

ACK

-Steffan

#12 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of X509_STORE

In reply to [email protected]...

Your patch has been applied to the master and release/2.4 branch.

commit f05665df4150c6a345eec5432a02fd799bea0f2c (master) commit 24bca7bee2ee5c48880a197ce9727bbc5a0149e5 (release/2.4)

Author: Emmanuel Deloget
Date:   Fri Feb 17 23:00:41 2017 +0100
     OpenSSL: don't use direct access to the internal of X509_STORE

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <8e6d66e3a9a40abb3d7c99c48ba59bad1037d0ef.1487368114.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14076.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#13 lore raw

RFC PATCH 3/15 OpenSSL: don't use direct access to the internal of X509_OBJECT

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_OBJECT. 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.

---
 configure.ac                     |  2 ++
 src/openvpn/openssl_compat.h     | 31 +++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c        |  5 ++---
 src/openvpn/ssl_verify_openssl.c |  2 +-
 4 files changed, 36 insertions(+), 4 deletions(-)
configure.ac +2 -0
index 415128c9f8687a53e4a73419f3048d07f66b70cc..789ad08fbaa3b3fc4c95d2b7a22332c0a93aeab4 100644
@@ -903,6 +903,8 @@ 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_STORE_get0_objects \
+			X509_OBJECT_free \
+			X509_OBJECT_get_type \
 		],
 		,
 		[]
src/openvpn/openssl_compat.h +31 -0
index 016008bc1705a41ee0ee09fecfc0b16b282cede3..458a6adbe2b3fcd5ea63dcea6596cc24315d463c 100644
@@ -86,4 +86,35 @@ X509_STORE_get0_objects(X509_STORE *store)
 }
 #endif
 
+#if !defined(HAVE_X509_OBJECT_FREE)
+/**
+ * Destroy a X509 object
+ *
+ * @param obj                X509 object
+ */
+static inline void
+X509_OBJECT_free(X509_OBJECT *obj)
+{
+    if (obj)
+    {
+        X509_OBJECT_free_contents(obj);
+        OPENSSL_free(obj);
+    }
+}
+#endif
+
+#if !defined(HAVE_X509_OBJECT_GET_TYPE)
+/**
+ * Get the type of an X509 object
+ *
+ * @param obj                X509 object
+ * @return                   The underlying object type
+ */
+static inline int
+X509_OBJECT_get_type(const X509_OBJECT *obj)
+{
+    return obj ? obj->type : X509_LU_FAIL;
+}
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +2 -3
index e57de43a748c89ff58ea00abade0b1c317013258..bf0f643f25439f71cbfe71bf5a7e8eb834b0f012 100644
@@ -905,11 +905,10 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
     {
         X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
-        if (obj->type == X509_LU_CRL)
+        if (X509_OBJECT_get_type(obj) == X509_LU_CRL)
         {
             sk_X509_OBJECT_delete(objs, i);
-            X509_OBJECT_free_contents(obj);
-            OPENSSL_free(obj);
+            X509_OBJECT_free(obj);
         }
     }
 
src/openvpn/ssl_verify_openssl.c +1 -1
index fabbb0c370b123f54ce4a1eaf5f9650b440f47f8..07975248035b48121d1383b47f40a56042bc7380 100644
@@ -721,7 +721,7 @@ tls_verify_crl_missing(const struct tls_options *opt)
     {
         X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
-        if (obj->type == X509_LU_CRL)
+        if (X509_OBJECT_get_type(obj) == X509_LU_CRL)
         {
             return false;
         }
Signature · 1 line
2.7.4
#14 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 03/15] OpenSSL: don't use direct access to the internal of X509_OBJECT

Quoted 94 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_OBJECT. 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.

---
 configure.ac                     |  2 ++
 src/openvpn/openssl_compat.h     | 31 +++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c        |  5 ++---
 src/openvpn/ssl_verify_openssl.c |  2 +-
 4 files changed, 36 insertions(+), 4 deletions(-)
configure.ac +2 -0
index 415128c9f8687a53e4a73419f3048d07f66b70cc..789ad08fbaa3b3fc4c95d2b7a22332c0a93aeab4 100644
@@ -903,6 +903,8 @@ 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_STORE_get0_objects \
+			X509_OBJECT_free \
+			X509_OBJECT_get_type \
 		],
 		,
 		[]
src/openvpn/openssl_compat.h +31 -0
index 016008bc1705a41ee0ee09fecfc0b16b282cede3..458a6adbe2b3fcd5ea63dcea6596cc24315d463c 100644
@@ -86,4 +86,35 @@ X509_STORE_get0_objects(X509_STORE *store)
 }
 #endif
 
+#if !defined(HAVE_X509_OBJECT_FREE)
+/**
+ * Destroy a X509 object
+ *
+ * @param obj                X509 object
+ */
+static inline void
+X509_OBJECT_free(X509_OBJECT *obj)
+{
+    if (obj)
+    {
+        X509_OBJECT_free_contents(obj);
+        OPENSSL_free(obj);
+    }
+}
+#endif
+
+#if !defined(HAVE_X509_OBJECT_GET_TYPE)
+/**
+ * Get the type of an X509 object
+ *
+ * @param obj                X509 object
+ * @return                   The underlying object type
+ */
+static inline int
+X509_OBJECT_get_type(const X509_OBJECT *obj)
+{
+    return obj ? obj->type : X509_LU_FAIL;
+}
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +2 -3
index e57de43a748c89ff58ea00abade0b1c317013258..bf0f643f25439f71cbfe71bf5a7e8eb834b0f012 100644
@@ -905,11 +905,10 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
     {
         X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
-        if (obj->type == X509_LU_CRL)
+        if (X509_OBJECT_get_type(obj) == X509_LU_CRL)
         {
             sk_X509_OBJECT_delete(objs, i);
-            X509_OBJECT_free_contents(obj);
-            OPENSSL_free(obj);
+            X509_OBJECT_free(obj);
         }
     }
 
src/openvpn/ssl_verify_openssl.c +0 -0
index fabbb0c370b123f54ce4a1eaf5f9650b440f47f8..07975248035b48121d1383b47f40a56042bc7380 100644

src/openvpn/ssl_verify_openssl.c tls_verify_crl_missing(const struct tls_options *opt) · line 727

Quoted 8 lines
src/openvpn/ssl_verify_openssl.c +1 -1
@@ -721,7 +721,7 @@ tls_verify_crl_missing(const struct tls_options *opt)
     {
         X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i);
         ASSERT(obj);
-        if (obj->type == X509_LU_CRL)
+        if (X509_OBJECT_get_type(obj) == X509_LU_CRL)
         {
             return false;
         }

ACK

-Steffan

#15 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of X509_OBJECT

In reply to [email protected]...

Your patch has been applied to the master and release/2.4 branch.

commit 47191f49890ee5c53fa78a8ce9bf96b9c8d27a82 (master) commit d782597ede843266fd2c7854a6f90ec7ce4bb92b (release/2.4)

Author: Emmanuel Deloget
Date:   Fri Feb 17 23:00:42 2017 +0100
     OpenSSL: don't use direct access to the internal of X509_OBJECT

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <c849c9778d2b2faa4eb4d31367b37d993da5eb85.1487368114.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14080.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#16 lore raw

RFC PATCH 4/15 OpenSSL: don't use direct access to the internal of RSA_METHOD

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including RSA_METHOD. 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.

---
 configure.ac                 |   9 +++
 src/openvpn/openssl_compat.h | 186 +++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  22 ++---
 3 files changed, 206 insertions(+), 11 deletions(-)
configure.ac +9 -0
index 789ad08fbaa3b3fc4c95d2b7a22332c0a93aeab4..6f31609d0aeedd2c7841d271ecadd1aa6f3b11da 100644
@@ -905,6 +905,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			X509_STORE_get0_objects \
 			X509_OBJECT_free \
 			X509_OBJECT_get_type \
+			RSA_meth_new \
+			RSA_meth_free \
+			RSA_meth_set_pub_enc \
+			RSA_meth_set_pub_dec \
+			RSA_meth_set_priv_enc \
+			RSA_meth_set_priv_dec \
+			RSA_meth_set_init \
+			RSA_meth_set_finish \
+			RSA_meth_set0_app_data \
 		],
 		,
 		[]
src/openvpn/openssl_compat.h +186 -0

196 lines not on this page · raw message

src/openvpn/ssl_openssl.c +11 -11
index bf0f643f25439f71cbfe71bf5a7e8eb834b0f012..f011e06702529ff34e91f6d0169d1adf8cc9d767 100644
@@ -978,7 +978,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    free((void *)rsa->meth);
+    RSA_meth_free(rsa->meth);
     rsa->meth = NULL;
     return 1;
 }
@@ -1053,16 +1053,16 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
     ASSERT(NULL != cert);
 
     /* allocate custom RSA method object */
-    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
-    rsa_meth->name = "OpenVPN external private key RSA Method";
-    rsa_meth->rsa_pub_enc = rsa_pub_enc;
-    rsa_meth->rsa_pub_dec = rsa_pub_dec;
-    rsa_meth->rsa_priv_enc = rsa_priv_enc;
-    rsa_meth->rsa_priv_dec = rsa_priv_dec;
-    rsa_meth->init = NULL;
-    rsa_meth->finish = rsa_finish;
-    rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
-    rsa_meth->app_data = NULL;
+    rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method",
+                            RSA_METHOD_FLAG_NO_CHECK);
+    check_malloc_return(rsa_meth);
+    RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc);
+    RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec);
+    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_set0_app_data(rsa_meth, NULL);
 
     /* allocate RSA object */
     rsa = RSA_new();
Signature · 1 line
2.7.4
#17 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 04/15] OpenSSL: don't use direct access to the internal of RSA_METHOD

Hi,

Quoted 74 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including RSA_METHOD. 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.

---
 configure.ac                 |   9 +++
 src/openvpn/openssl_compat.h | 186 +++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  22 ++---
 3 files changed, 206 insertions(+), 11 deletions(-)
configure.ac +9 -0
index 789ad08fbaa3b3fc4c95d2b7a22332c0a93aeab4..6f31609d0aeedd2c7841d271ecadd1aa6f3b11da 100644
@@ -905,6 +905,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			X509_STORE_get0_objects \
 			X509_OBJECT_free \
 			X509_OBJECT_get_type \
+			RSA_meth_new \
+			RSA_meth_free \
+			RSA_meth_set_pub_enc \
+			RSA_meth_set_pub_dec \
+			RSA_meth_set_priv_enc \
+			RSA_meth_set_priv_dec \
+			RSA_meth_set_init \
+			RSA_meth_set_finish \
+			RSA_meth_set0_app_data \
 		],
 		,
 		[]
src/openvpn/openssl_compat.h +23 -0
index 458a6adbe2b3fcd5ea63dcea6596cc24315d463c..b1748754f821f472cf9ed7083ade918336c9b075 100644
@@ -41,6 +41,8 @@
 #include "config-msvc.h"
 #endif
 
+#include "buffer.h"
+
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 
@@ -117,4 +119,188 @@ X509_OBJECT_get_type(const X509_OBJECT *obj)
 }
 #endif
 
+#if !defined(HAVE_RSA_METH_NEW)
+/**
+ * Allocate a new RSA method object
+ *
+ * @param name               The object name
+ * @param flags              Configuration flags
+ * @return                   A new RSA method object
+ */
+static inline RSA_METHOD *
+RSA_meth_new(const char *name, int flags)
+{
+    RSA_METHOD *rsa_meth = NULL;
+    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
+    rsa_meth->name = name;
+    rsa_meth->flags = flags;
+    return rsa_meth;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_FREE)
+/**

src/openvpn/openssl_compat.h X509_OBJECT_get_type(const X509_OBJECT *obj) · line 152

Quoted 10 lines
src/openvpn/openssl_compat.h +10 -0
+ * Free an existing RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ */
+static inline void
+RSA_meth_free(RSA_METHOD *meth)
+{
+    free(meth);
+}
+#endif

I think it would be nicer to more closely mimic the 1.1 behaviour in RSA_meth_{new,free}(), and copy the name string in new() and free it again in free(). That could prevent a future use-after-free that would occur for pre-1.1.0, but not 1.1.0+:

  char *mystring = calloc(50, 1);
  RSA_METHOD *meth = RSA_meth_new(mystring, 0);
  free(mystring);

  meth.smoke();
       ^^ might cause problems

(Hint: use string_alloc(x, NULL).)

Quoted 159 lines
src/openvpn/openssl_compat.h +153 -0
+
+#if !defined(HAVE_RSA_METH_SET_PUB_ENC)
+/**
+ * Set the public encoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param pub_enc            the public encoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_pub_enc(RSA_METHOD *meth,
+                     int (*pub_enc) (int flen, const unsigned char *from,
+                                     unsigned char *to, RSA *rsa,
+                                     int padding))
+{
+    if (meth)
+    {
+        meth->rsa_pub_enc = pub_enc;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PUB_DEC)
+/**
+ * Set the public decoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param pub_dec            the public decoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_pub_dec(RSA_METHOD *meth,
+                     int (*pub_dec) (int flen, const unsigned char *from,
+                                     unsigned char *to, RSA *rsa,
+                                     int padding))
+{
+    if (meth)
+    {
+        meth->rsa_pub_dec = pub_dec;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PRIV_ENC)
+/**
+ * Set the private encoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param priv_enc           the private encoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_priv_enc(RSA_METHOD *meth,
+                      int (*priv_enc) (int flen, const unsigned char *from,
+                                       unsigned char *to, RSA *rsa,
+                                       int padding))
+{
+    if (meth)
+    {
+        meth->rsa_priv_enc = priv_enc;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PRIV_DEC)
+/**
+ * Set the private decoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param priv_dec           the private decoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_priv_dec(RSA_METHOD *meth,
+                      int (*priv_dec) (int flen, const unsigned char *from,
+                                       unsigned char *to, RSA *rsa,
+                                       int padding))
+{
+    if (meth)
+    {
+        meth->rsa_priv_dec = priv_dec;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_INIT)
+/**
+ * Set the init function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param init               the init function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_init(RSA_METHOD *meth, int (*init) (RSA *rsa))
+{
+    if (meth)
+    {
+        meth->init = init;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_FINISH)
+/**
+ * Set the finish function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param finish             the finish function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
+{
+    if (meth)
+    {
+        meth->finish = finish;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET0_APP_DATA)
+/**
+ * Set the application data of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param app_data           Application data
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
+{
+    if (meth)
+    {
+        meth->app_data = app_data;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +0 -0
index bf0f643f25439f71cbfe71bf5a7e8eb834b0f012..f011e06702529ff34e91f6d0169d1adf8cc9d767 100644

src/openvpn/ssl_openssl.c rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i · line 984

Quoted 8 lines
src/openvpn/ssl_openssl.c +1 -1
@@ -978,7 +978,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    free((void *)rsa->meth);
+    RSA_meth_free(rsa->meth);
     rsa->meth = NULL;
     return 1;
 }

This change still works, but he follow up change in this method in 07/15 causes problems:

    static int
    rsa_finish(RSA *rsa)
    {
   -    RSA_meth_free(rsa->meth);
   -    rsa->meth = NULL;
   +    RSA_METHOD *meth = (RSA_METHOD *)RSA_get_method(rsa);
   +    RSA_meth_free(meth);
   +    RSA_set_method(rsa, NULL);
        return 1;
    }

Casting away const on the object returned by RSA_get_method() is a smell, but it really fails because RSA_set_method(rsa, NULL) calls rsa->meth->finish(), which is implemented by this very function. That means that RSA_meth_free() will perform a double free on meth->name.

I briefly looked into a fix, but didn't immediately see a nice solution here. At least the RSA_set_method(rsa, RSA_get_default_method()) doesn't work either, because you'll end up with rsa_finish() and RSA_set_method() calling each other infinitely...

(Noting this here, because the fix for 07 might cause changes to this patch too.)

Quoted 18 lines
src/openvpn/ssl_openssl.c +3 -10
@@ -1053,16 +1053,16 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
     ASSERT(NULL != cert);
 
     /* allocate custom RSA method object */
-    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
-    rsa_meth->name = "OpenVPN external private key RSA Method";
-    rsa_meth->rsa_pub_enc = rsa_pub_enc;
-    rsa_meth->rsa_pub_dec = rsa_pub_dec;
-    rsa_meth->rsa_priv_enc = rsa_priv_enc;
-    rsa_meth->rsa_priv_dec = rsa_priv_dec;
-    rsa_meth->init = NULL;
-    rsa_meth->finish = rsa_finish;
-    rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
-    rsa_meth->app_data = NULL;
+    rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method",
+                            RSA_METHOD_FLAG_NO_CHECK);
+    check_malloc_return(rsa_meth);

src/openvpn/ssl_openssl.c tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, · line 1068

Quoted 10 lines
src/openvpn/ssl_openssl.c +7 -0
+    RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc);
+    RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec);
+    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_set0_app_data(rsa_meth, NULL);
 
     /* allocate RSA object */
     rsa = RSA_new();

-Steffan

#18 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 04/15] OpenSSL: don't use direct access to the internal of RSA_METHOD

Hi Steffan,

Quoted 84 lines · Steffan Karger

Hi,

Quoted 81 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including RSA_METHOD. 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.

---
 configure.ac                 |   9 +++
 src/openvpn/openssl_compat.h | 186 +++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  22 ++---
 3 files changed, 206 insertions(+), 11 deletions(-)
configure.ac +9 -0
index 789ad08fbaa3b3fc4c95d2b7a22332c0a93aeab4..6f31609d0aeedd2c7841d271ecadd1aa6f3b11da 100644
@@ -905,6 +905,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
                      X509_STORE_get0_objects \
                      X509_OBJECT_free \
                      X509_OBJECT_get_type \
+                     RSA_meth_new \
+                     RSA_meth_free \
+                     RSA_meth_set_pub_enc \
+                     RSA_meth_set_pub_dec \
+                     RSA_meth_set_priv_enc \
+                     RSA_meth_set_priv_dec \
+                     RSA_meth_set_init \
+                     RSA_meth_set_finish \
+                     RSA_meth_set0_app_data \
              ],
              ,
              []
src/openvpn/openssl_compat.h +30 -0
index 458a6adbe2b3fcd5ea63dcea6596cc24315d463c..b1748754f821f472cf9ed7083ade918336c9b075 100644
@@ -41,6 +41,8 @@
 #include "config-msvc.h"
 #endif
 
+#include "buffer.h"
+
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 
@@ -117,4 +119,188 @@ X509_OBJECT_get_type(const X509_OBJECT *obj)
 }
 #endif
 
+#if !defined(HAVE_RSA_METH_NEW)
+/**
+ * Allocate a new RSA method object
+ *
+ * @param name               The object name
+ * @param flags              Configuration flags
+ * @return                   A new RSA method object
+ */
+static inline RSA_METHOD *
+RSA_meth_new(const char *name, int flags)
+{
+    RSA_METHOD *rsa_meth = NULL;
+    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
+    rsa_meth->name = name;
+    rsa_meth->flags = flags;
+    return rsa_meth;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_FREE)
+/**
+ * Free an existing RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ */
+static inline void
+RSA_meth_free(RSA_METHOD *meth)
+{
Quoted 8 lines

src/openvpn/openssl_compat.h X509_OBJECT_get_type(const X509_OBJECT *obj) · line 152

Quoted 3 lines
src/openvpn/openssl_compat.h +3 -0
+    free(meth);
+}
+#endif

I think it would be nicer to more closely mimic the 1.1 behaviour in RSA_meth_{new,free}(), and copy the name string in new() and free it again in free(). That could prevent a future use-after-free that would occur for pre-1.1.0, but not 1.1.0+:

I failed to see that when I implemented my solution. I'll give a look as soon as possible.

Quoted 196 lines
  char *mystring = calloc(50, 1);
  RSA_METHOD *meth = RSA_meth_new(mystring, 0);
  free(mystring);

  meth.smoke();
       ^^ might cause problems

(Hint: use string_alloc(x, NULL).)

Quoted 159 lines
src/openvpn/openssl_compat.h +153 -0
+
+#if !defined(HAVE_RSA_METH_SET_PUB_ENC)
+/**
+ * Set the public encoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param pub_enc            the public encoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_pub_enc(RSA_METHOD *meth,
+                     int (*pub_enc) (int flen, const unsigned char *from,
+                                     unsigned char *to, RSA *rsa,
+                                     int padding))
+{
+    if (meth)
+    {
+        meth->rsa_pub_enc = pub_enc;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PUB_DEC)
+/**
+ * Set the public decoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param pub_dec            the public decoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_pub_dec(RSA_METHOD *meth,
+                     int (*pub_dec) (int flen, const unsigned char *from,
+                                     unsigned char *to, RSA *rsa,
+                                     int padding))
+{
+    if (meth)
+    {
+        meth->rsa_pub_dec = pub_dec;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PRIV_ENC)
+/**
+ * Set the private encoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param priv_enc           the private encoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_priv_enc(RSA_METHOD *meth,
+                      int (*priv_enc) (int flen, const unsigned char *from,
+                                       unsigned char *to, RSA *rsa,
+                                       int padding))
+{
+    if (meth)
+    {
+        meth->rsa_priv_enc = priv_enc;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PRIV_DEC)
+/**
+ * Set the private decoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param priv_dec           the private decoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_priv_dec(RSA_METHOD *meth,
+                      int (*priv_dec) (int flen, const unsigned char *from,
+                                       unsigned char *to, RSA *rsa,
+                                       int padding))
+{
+    if (meth)
+    {
+        meth->rsa_priv_dec = priv_dec;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_INIT)
+/**
+ * Set the init function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param init               the init function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_init(RSA_METHOD *meth, int (*init) (RSA *rsa))
+{
+    if (meth)
+    {
+        meth->init = init;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_FINISH)
+/**
+ * Set the finish function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param finish             the finish function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
+{
+    if (meth)
+    {
+        meth->finish = finish;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET0_APP_DATA)
+/**
+ * Set the application data of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param app_data           Application data
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
+{
+    if (meth)
+    {
+        meth->app_data = app_data;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +0 -0
index bf0f643f25439f71cbfe71bf5a7e8eb834b0f012..f011e06702529ff34e91f6d0169d1adf8cc9d767 100644

src/openvpn/ssl_openssl.c rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i · line 984

Quoted 8 lines
src/openvpn/ssl_openssl.c +1 -1
@@ -978,7 +978,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    free((void *)rsa->meth);
+    RSA_meth_free(rsa->meth);
     rsa->meth = NULL;
     return 1;
 }

This change still works, but he follow up change in this method in 07/15 causes problems:

    static int
    rsa_finish(RSA *rsa)
    {
   -    RSA_meth_free(rsa->meth);
   -    rsa->meth = NULL;
   +    RSA_METHOD *meth = (RSA_METHOD *)RSA_get_method(rsa);
   +    RSA_meth_free(meth);
   +    RSA_set_method(rsa, NULL);
        return 1;
    }

Casting away const on the object returned by RSA_get_method() is a smell, but it really fails because RSA_set_method(rsa, NULL) calls rsa->meth->finish(), which is implemented by this very function. That means that RSA_meth_free() will perform a double free on meth->name.

Quoted 4 lines

I briefly looked into a fix, but didn't immediately see a nice solution here. At least the RSA_set_method(rsa, RSA_get_default_method()) doesn't work either, because you'll end up with rsa_finish() and RSA_set_method() calling each other infinitely...

Ouch. I failed to see that as well. Sorry :)

I'll try to find a better solution to this issue as well.

Quoted 28 lines

(Noting this here, because the fix for 07 might cause changes to this patch too.)

Quoted 25 lines
src/openvpn/ssl_openssl.c +10 -10
@@ -1053,16 +1053,16 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
     ASSERT(NULL != cert);
 
     /* allocate custom RSA method object */
-    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
-    rsa_meth->name = "OpenVPN external private key RSA Method";
-    rsa_meth->rsa_pub_enc = rsa_pub_enc;
-    rsa_meth->rsa_pub_dec = rsa_pub_dec;
-    rsa_meth->rsa_priv_enc = rsa_priv_enc;
-    rsa_meth->rsa_priv_dec = rsa_priv_dec;
-    rsa_meth->init = NULL;
-    rsa_meth->finish = rsa_finish;
-    rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
-    rsa_meth->app_data = NULL;
+    rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method",
+                            RSA_METHOD_FLAG_NO_CHECK);
+    check_malloc_return(rsa_meth);
+    RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc);
+    RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec);
+    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_set0_app_data(rsa_meth, NULL);
 
Quoted 6 lines

src/openvpn/ssl_openssl.c tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, · line 1068

Quoted 3 lines
src/openvpn/ssl_openssl.c +0 -0
     /* allocate RSA object */
     rsa = RSA_new();

-Steffan

Best regards,

-- Emmanuel Deloget

#19 lore raw

RFC PATCH 5/15 OpenSSL: don't use direct access to the internal of X509

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

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).

Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library.

---
 configure.ac                     |  1 +
 src/openvpn/openssl_compat.h     | 15 +++++++++++++++
 src/openvpn/ssl_openssl.c        |  3 ++-
 src/openvpn/ssl_verify_openssl.c | 28 +++++++++++++++++++---------
 4 files changed, 37 insertions(+), 10 deletions(-)
configure.ac +1 -0
index 6f31609d0aeedd2c7841d271ecadd1aa6f3b11da..c41db3effbb26318be4f44009a5055e808b89b56 100644
@@ -902,6 +902,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 \
src/openvpn/openssl_compat.h +15 -0
index b1748754f821f472cf9ed7083ade918336c9b075..6a89b91b05e0370a50ac5a1cae20ae659e6c7634 100644
@@ -74,6 +74,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
src/openvpn/ssl_openssl.c +2 -1
index f011e06702529ff34e91f6d0169d1adf8cc9d767..b683961d9e4e79b9ee04cfa7ecd1b377ade9651b 100644
@@ -1073,7 +1073,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 */
src/openvpn/ssl_verify_openssl.c +19 -9
index 07975248035b48121d1383b47f40a56042bc7380..edc709b89eb05bca895639dde606b29f8e1f7024 100644
@@ -285,18 +285,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;
 }
 
@@ -573,13 +575,21 @@ 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 wierd thing that
+         * prevent it to take a const argument
+         */
+        return X509_check_purpose((X509 *)peer_cert, X509_PURPOSE_SSL_CLIENT, 0) ?
+	       SUCCESS : FAILURE;
     }
     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 wierd thing that
+         * prevent it to take a const argument
+         */
+        return X509_check_purpose((X509 *)peer_cert, X509_PURPOSE_SSL_SERVER, 0) ?
+	       SUCCESS : FAILURE;
     }
 
     return FAILURE;
Signature · 1 line
2.7.4
#20 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

Hi,

Quoted 6 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

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.

Quoted 7 lines

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).

The nsCertType x509 extension is very old, and replaced by keyUsage and extendedKeyUsage (supported by OpenVPN via --remote-cert-tls or --remote-cert-ku and --remote-cert-eku).

Changing this to the stricter API without warning will probably break some people's setups with certs that do have nsCertType set, but not keyUsage and/or extendedKeyUsage, while leaving them guessing why.

So, what I propose instead is:
* remove all the nsCertType code (except the option in add_option())
* update the help strings and man page to indicate that --ns-cert-type
is no longer supported and --remote-cert-tls should be used instead
* in add_option(), if the option is enabled in a config file, act as if
--remote-cert-tls was specified correspondingly, and print a clear warning that --ns-cert-type is no longer supported and stricter checks are enabled instead.

Quoted 110 lines

Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library.

---
 configure.ac                     |  1 +
 src/openvpn/openssl_compat.h     | 15 +++++++++++++++
 src/openvpn/ssl_openssl.c        |  3 ++-
 src/openvpn/ssl_verify_openssl.c | 28 +++++++++++++++++++---------
 4 files changed, 37 insertions(+), 10 deletions(-)
configure.ac +1 -0
index 6f31609d0aeedd2c7841d271ecadd1aa6f3b11da..c41db3effbb26318be4f44009a5055e808b89b56 100644
@@ -902,6 +902,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 \
src/openvpn/openssl_compat.h +15 -0
index b1748754f821f472cf9ed7083ade918336c9b075..6a89b91b05e0370a50ac5a1cae20ae659e6c7634 100644
@@ -74,6 +74,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
src/openvpn/ssl_openssl.c +2 -1
index f011e06702529ff34e91f6d0169d1adf8cc9d767..b683961d9e4e79b9ee04cfa7ecd1b377ade9651b 100644
@@ -1073,7 +1073,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 */
src/openvpn/ssl_verify_openssl.c +13 -8
index 07975248035b48121d1383b47f40a56042bc7380..edc709b89eb05bca895639dde606b29f8e1f7024 100644
@@ -285,18 +285,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;
 }
 
@@ -573,13 +575,21 @@ 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 wierd thing that
+         * prevent it to take a const argument
+         */
+        return X509_check_purpose((X509 *)peer_cert, X509_PURPOSE_SSL_CLIENT, 0) ?
+	       SUCCESS : FAILURE;
     }
     if (usage == NS_CERT_CHECK_SERVER)
     {
-        return ((peer_cert->ex_flags & EXFLAG_NSCERT)

src/openvpn/ssl_verify_openssl.c x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) · line 595

Quoted 10 lines
src/openvpn/ssl_verify_openssl.c +6 -1
-                && (peer_cert->ex_nscert & NS_SSL_SERVER))  ? SUCCESS : FAILURE;
+        /*
+         * Unfortunately, X509_check_purpose() does some wierd thing that
+         * prevent it to take a const argument
+         */
+        return X509_check_purpose((X509 *)peer_cert, X509_PURPOSE_SSL_SERVER, 0) ?
+	       SUCCESS : FAILURE;
     }
 
     return FAILURE;

If we are to use X509_check_purpose() (see my comments above), we should not cast away const here, but rather remove the const qualified from the peer_cert argument. Casting away const is bad, in particular if a comment on the function states that it really can't take a const argument because it changes the object.

-Steffan

#21 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

Hi,

Quoted 8 lines · Steffan Karger

So, what I propose instead is:
* remove all the nsCertType code (except the option in add_option())
* update the help strings and man page to indicate that --ns-cert-type
is no longer supported and --remote-cert-tls should be used instead
* in add_option(), if the option is enabled in a config file, act as if
--remote-cert-tls was specified correspondingly, and print a clear warning that --ns-cert-type is no longer supported and stricter checks are enabled instead.

Mmmmh. Is there a way to get the old behaviour with OpenSSL 1.1?

We decided that we do want 1.1 compatibility in release/2.4, but what you propose might break people's working config when upgrading from 2.4.1 to 2.4.2 - bad enough if we make mistakes, but if there is an alternative to consciously changing cert validation behaviour in the middle of a release train, we should look again...

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#22 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

Hi,

Quoted 10 lines · Gert Doering
Quoted 8 lines · Steffan Karger

So, what I propose instead is:
* remove all the nsCertType code (except the option in add_option())
* update the help strings and man page to indicate that --ns-cert-type
is no longer supported and --remote-cert-tls should be used instead
* in add_option(), if the option is enabled in a config file, act as if
--remote-cert-tls was specified correspondingly, and print a clear warning that --ns-cert-type is no longer supported and stricter checks are enabled instead.

Quoted 7 lines

Mmmmh. Is there a way to get the old behaviour with OpenSSL 1.1?

We decided that we do want 1.1 compatibility in release/2.4, but what you propose might break people's working config when upgrading from 2.4.1 to 2.4.2 - bad enough if we make mistakes, but if there is an alternative to consciously changing cert validation behaviour in the middle of a release train, we should look again...

So I looked again, and there really seems to be no way to get the old behaviour with OpenSSL 1.1. However, the exact behaviour of X509_check_purpose() is not as strict as I initially thought. The current patch basically adds the following checks:
* if the cert has key usage set, it must be correct
* if the cert has extended key usage set, it must be correct
* if the cert has the CA flag set, it must be done correctly

These are fairly low-risk. I'd expect quite some issues if we would reject certs *without* (extended) key usage set, but if (e)ku is set, this will most likely be done correctly. Or in other words, we might reject weird certificates, but not proper certificates.

All in all, I think the original patch (after fixing const correctness) is fine.

As a last resort, we could consider keeping the old code inside #if OSSL_VER < 1.1.0 in release/2.4, but that might just create more confusion...

-Steffan

#23 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

Hello,

Quoted 21 lines · Steffan Karger

Hi,

Quoted 10 lines · Gert Doering
Quoted 8 lines · Steffan Karger

So, what I propose instead is:
* remove all the nsCertType code (except the option in add_option())
* update the help strings and man page to indicate that --ns-cert-type
is no longer supported and --remote-cert-tls should be used instead
* in add_option(), if the option is enabled in a config file, act as if
--remote-cert-tls was specified correspondingly, and print a clear warning that --ns-cert-type is no longer supported and stricter checks are enabled instead.

Quoted 7 lines

Mmmmh. Is there a way to get the old behaviour with OpenSSL 1.1?

We decided that we do want 1.1 compatibility in release/2.4, but what you propose might break people's working config when upgrading from 2.4.1 to 2.4.2 - bad enough if we make mistakes, but if there is an alternative to consciously changing cert validation behaviour in the middle of a release train, we should look again...

Quoted 7 lines

So I looked again, and there really seems to be no way to get the old behaviour with OpenSSL 1.1. However, the exact behaviour of X509_check_purpose() is not as strict as I initially thought. The current patch basically adds the following checks:
* if the cert has key usage set, it must be correct
* if the cert has extended key usage set, it must be correct
* if the cert has the CA flag set, it must be done correctly

When I coded this part, I searched for a long time before resorting to using this function. It's true that the library does more check, yet I didn't find any way to not do them, as the necessary members are not available through getters.

However, my understanding is that OpenSSL does a full, correct check, and that certificates that does not pass this check are probably not correct - or at least, they hide some weird issues that could make them a bit dangerous to use. Of course, I might be wrong. The certificates I tested were valid w.r.t. this new code and I'm now sure how I can generate certificates that do not pass.

Quoted 4 lines

These are fairly low-risk. I'd expect quite some issues if we would reject certs *without* (extended) key usage set, but if (e)ku is set, this will most likely be done correctly. Or in other words, we might reject weird certificates, but not proper certificates.

Yet, rejecting certificates might pose problems in the organisations that use them, and they should be warned by (at least) and intermediate release that their certificates going to be rejected. So, after a bit of thinking I would do :

1/ check the certificate with X209_check_purpose()
2/ on failure, for OpenSSL < 1.1.0, warn the user that the certificates are probably not fully correct, and do the old check. If it pass, continue

Quoted 6 lines

All in all, I think the original patch (after fixing const correctness) is fine.

As a last resort, we could consider keeping the old code inside #if OSSL_VER < 1.1.0 in release/2.4, but that might just create more confusion...

Unfortunately, I am overbooked right now and I'm not sure I'll be able to do this fast (say, in less than 2 weeks). I'd be grateful of someone else does it.

Quoted 1 line

-Steffan

Best regards,

-- Emmanuel Deloget

#24 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

In reply to Steffan Karger
Quoted 3 lines · Steffan Karger

As a last resort, we could consider keeping the old code inside #if OSSL_VER < 1.1.0 in release/2.4, but that might just create more confusion...

Just a very quick thought here ... I do dislike different behaviours depending on which OpenSSL version being used. But given that this feature is already deprecated and even removed in OpenSSL-1.1, I think that gives us some options.

I agree with Gert that breaking --ns-cert-type isn't good at all. However, consider when people upgrade from OpenSSL v1.0 to v1.1 - that is most commonly when there is major distro update. It is not something which happens "mid-term", as OpenSSL is quite commonly used by lots of base system packages these days.

Regardless of OpenSSL version, I agree to loudly deprecate --ns-cert-type, through documentation, --help and log files.

But I think we need to carry the existing behaviour for --ns-cert-type when built against OpenSSL v1.0. And we can solve through some compatibility wrapper when built against OpenSSL v1.1 - with even louder warnings in the logs that this may break apart.

The reason I say this, is that Fedora users are quite unhappy that --tls-remote disappeared in v2.4.0 *despite* a more recent NetworkManager-OpenVPN plug-in actually making it easy to switch to --verify-x509-name. But IIRC, this wasn't backported to all older and still valid Fedora releases, so that caused additional pain for the
users. And don't get me started with the attempt of temporarily build
against mbed TLS instead of OpenSSL in Fedora Rawhide (which will become Fedora 26), as that broke lots of configurations with CA certificates using RSA 1024 bit keys. All this results in very little OpenVPN 2.4 adaptation among many Fedora users.

I can barely imagine what happens if we break --ns-cert-type on top of that ... Just that the behaviour might change for a minority of users in when Fedora 26 hits the streets, with OpenSSL v1.1, might hit us bad again. But at least with OpenSSL v1.1, many users knows that things will be somewhat different too. And we can actually point at OpenSSL and explain why it broke, which is not something we could do with the --tls-remote option.

Just my way too many cents ..... :)

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#25 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

Hi everyone,

I got some time to try to fix all that stuff.

First,

Quoted 5 lines · David Sommerseth
Quoted 3 lines · Steffan Karger

As a last resort, we could consider keeping the old code inside #if OSSL_VER < 1.1.0 in release/2.4, but that might just create more confusion...

​I think I found a solution -- see later in the email.​

I had a closer look to the corresponding code to see what are the differences between the old check and the new one -- and indeed, the discrepancies might only happen if the tested certificate is kind-of-weird. For exemple, a client certificate:

* has the client bit set
* has no key, or has a key but the key usage is neither for signature nor for key agreement
* is not used to auth a client

​If a user creates a Frankenstein certificate that look like this, it might be a good idea to warn him that such certificate is very likely to be refused in the near future (one can have a similar reasonning about server certificates).

Quoted 12 lines

Just a very quick thought here ... I do dislike different behaviours depending on which OpenSSL version being used. But given that this feature is already deprecated and even removed in OpenSSL-1.1, I think that gives us some options.

I agree with Gert that breaking --ns-cert-type isn't good at all. However, consider when people upgrade from OpenSSL v1.0 to v1.1 - that is most commonly when there is major distro update. It is not something which happens "mid-term", as OpenSSL is quite commonly used by lots of base system packages these days.

Quoted 8 lines

Regardless of OpenSSL version, I agree to loudly deprecate --ns-cert-type, through documentation, --help and log files.

But I think we need to carry the existing behaviour for --ns-cert-type when built against OpenSSL v1.0. And we can solve through some compatibility wrapper when built against OpenSSL v1.1 - with even louder warnings in the logs that this may break apart.

​Fortunately, I think I found a solution that would help when using OpenSSL 1.1. Idealy, this should be a call to X509_check_purpose(.., X509_PURPOSE_SSL_*_WEAK, ...)​ but I don't think the OpenSSL developers will accept such a change :)

It might be possible to use the X509_get_ext_d2i() call like this:

void *ns = X509_get_ext_d2i(x, NID_netscape_cert_type,

                            NULL, NULL);

​In this case, the ​obtained ns object contains the data we're interested in:

* if it exists, then EXFLAG_NSCERT is set
* if not null, ns is of type ASN1_BIT_STRING, and this type is not opaque (yep, sir).

​So the code would look like:

​ASN1_BIT_STRING *ns;
result_t result = FAILURE;
ns = X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL); if (ns)

{
    if (ns->length > 0)
    {
        int flags = ns->data[0];
        if (flags & NS_SSL_CLIENT)
        {
            result = SUCCESS;
        }
    }
    ASN1_BIT_STRING_free(ns);
}

​For the record, it's the code ​that is used within function x509v3_cache_extensions() which builds the X509 flags we are using so I'm failry confident it's the right thing to do (but it's a bit convoluted and I don't like it much).

​Good news: the same code should work with nearly all the previous versions of OpenSSL.

Quoted 9 lines

​<snip>

--
kind regards,

David Sommerseth
OpenVPN Technologies, Inc

I'll post my new patches as soon as I get over every issues that have been talked on the ML (is that even a valid sentence?)

​Best regards,

-- Emmanuel Deloget​

#26 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

Hi,

I'm not sure why but it seems this mail (that I send yesterday) never found its way to the ML. So I re-send it.

Sorry for the inconvenience.

BR,

-- Emmanuel Deloget

Quoted 124 lines · Emmanuel Deloget

Hi everyone,

I got some time to try to fix all that stuff.

First,

Quoted 5 lines · David Sommerseth
Quoted 3 lines · Steffan Karger

As a last resort, we could consider keeping the old code inside #if OSSL_VER < 1.1.0 in release/2.4, but that might just create more confusion...

​I think I found a solution -- see later in the email.​

I had a closer look to the corresponding code to see what are the differences between the old check and the new one -- and indeed, the discrepancies might only happen if the tested certificate is kind-of-weird. For exemple, a client certificate:

* has the client bit set
* has no key, or has a key but the key usage is neither for signature nor for key agreement
* is not used to auth a client

​If a user creates a Frankenstein certificate that look like this, it might be a good idea to warn him that such certificate is very likely to be refused in the near future (one can have a similar reasonning about server certificates).

Quoted 12 lines

Just a very quick thought here ... I do dislike different behaviours depending on which OpenSSL version being used. But given that this feature is already deprecated and even removed in OpenSSL-1.1, I think that gives us some options.

I agree with Gert that breaking --ns-cert-type isn't good at all. However, consider when people upgrade from OpenSSL v1.0 to v1.1 - that is most commonly when there is major distro update. It is not something which happens "mid-term", as OpenSSL is quite commonly used by lots of base system packages these days.

Quoted 8 lines

Regardless of OpenSSL version, I agree to loudly deprecate --ns-cert-type, through documentation, --help and log files.

But I think we need to carry the existing behaviour for --ns-cert-type when built against OpenSSL v1.0. And we can solve through some compatibility wrapper when built against OpenSSL v1.1 - with even louder warnings in the logs that this may break apart.

​Fortunately, I think I found a solution that would help when using OpenSSL 1.1. Idealy, this should be a call to X509_check_purpose(.., X509_PURPOSE_SSL_*_WEAK, ...)​ but I don't think the OpenSSL developers will accept such a change :)

It might be possible to use the X509_get_ext_d2i() call like this:

void *ns = X509_get_ext_d2i(x, NID_netscape_cert_type,

                            NULL, NULL);

​In this case, the ​obtained ns object contains the data we're interested in:

* if it exists, then EXFLAG_NSCERT is set
* if not null, ns is of type ASN1_BIT_STRING, and this type is not opaque (yep, sir).

​So the code would look like:

​ASN1_BIT_STRING *ns;
result_t result = FAILURE;
ns = X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL); if (ns)

{
    if (ns->length > 0)
    {
        int flags = ns->data[0];
        if (flags & NS_SSL_CLIENT)
        {
            result = SUCCESS;
        }
    }
    ASN1_BIT_STRING_free(ns);
}

​For the record, it's the code ​that is used within function x509v3_cache_extensions() which builds the X509 flags we are using so I'm failry confident it's the right thing to do (but it's a bit convoluted and I don't like it much).

​Good news: the same code should work with nearly all the previous versions of OpenSSL.

Quoted 9 lines

​<snip>

--
kind regards,

David Sommerseth
OpenVPN Technologies, Inc

I'll post my new patches as soon as I get over every issues that have been talked on the ML (is that even a valid sentence?)

​Best regards,

-- Emmanuel Deloget​

#27 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 05/15] OpenSSL: don't use direct access to the internal of X509

Hi,

Quoted 4 lines · Emmanuel Deloget

I'm not sure why but it seems this mail (that I send yesterday) never found its way to the ML. So I re-send it.

Sorry for the inconvenience.

According to

https://www.mail-archive.com/[email protected]/msg14307.html

it arrived fine :-)

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#28 lore raw

Re: [Openvpn-devel] OpenSSL 1.1 patch set - status?

In reply to Emmanuel Deloget

Hi Emmanuel,

Quoted 3 lines · Emmanuel Deloget

I'll post my new patches as soon as I get over every issues that have been talked on the ML (is that even a valid sentence?)

I'm wondering where this got stuck - are you waiting for us to move forward (like, missing review of parts of the patch set), or are we waiting for you, and you've been busy?

We didn't really follow up on this from our end since the CVEs and 2.4.2 got in the way - but I think now would be a good time to move ahead with this...

thanks,

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#29 lore raw

Re: [Openvpn-devel] OpenSSL 1.1 patch set - status?

Hi Gert,

Quoted 11 lines · Gert Doering

Hi Emmanuel,

Quoted 3 lines · Emmanuel Deloget

I'll post my new patches as soon as I get over every issues that have been talked on the ML (is that even a valid sentence?)

I'm wondering where this got stuck - are you waiting for us to move forward (like, missing review of parts of the patch set), or are we waiting for you, and you've been busy?

Problem is that I'm working in a more-than-full-time manner on way-too-many-other subjects :)

Quoted 3 lines

We didn't really follow up on this from our end since the CVEs and 2.4.2 got in the way - but I think now would be a good time to move ahead with this...

I have a git tree out there that I have not fully tested yet. It compiles OK with OpenSSL 0.9.8, 1.0.0, 1.0.1, 1.0.2 and 1.1.0 but I haven't checked the behavior.

The main difference with the previous version of the patch is the way the certificate purpose is checked.

A) we do a fairly full check of the purpose using X509_check_purpose(). This check is harder that the previous version

B) if that fails, we check for the certificate purpose using a lighter method which is strictly equivalent to what was done before (it uses X509_get_ext_d2i() to fetch the certificate type from within the certificate).

The branch is available for viewing on github at
https://github.com/emmanuel-deloget/openvpn/tree/openssl-1.1-v6.

The followup emails contains the 7 patches which are needed to finish the work.

BR,

-- Emmanuel Deloget

#30 lore raw

PATCH 1/7 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.

Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library.

---
 configure.ac                     |  1 +
 src/openvpn/openssl_compat.h     | 15 ++++++++++
 src/openvpn/ssl_openssl.c        |  3 +-
 src/openvpn/ssl_verify_openssl.c | 64 ++++++++++++++++++++++++++++++++++------
 4 files changed, 73 insertions(+), 10 deletions(-)
configure.ac +1 -0
index 7d3fce5b..9d5e340b 100644
@@ -922,6 +922,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 \
src/openvpn/openssl_compat.h +15 -0
index 92f014d5..29a7588c 100644
@@ -74,6 +74,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
src/openvpn/ssl_openssl.c +2 -1
index 645ccf51..a082c3cd 100644
@@ -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 */
src/openvpn/ssl_verify_openssl.c +55 -9

86 lines not on this page · raw message

Signature · 1 line
2.11.0
#31 lore raw

PATCH 2/7 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.

---
 configure.ac                 |  3 +++
 src/openvpn/openssl_compat.h | 42 ++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  6 +++---
 3 files changed, 48 insertions(+), 3 deletions(-)
configure.ac +3 -0
index 9d5e340b..a92e8142 100644
@@ -926,6 +926,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 \
src/openvpn/openssl_compat.h +42 -0

48 lines not on this page · raw message

src/openvpn/ssl_openssl.c +3 -3
index a082c3cd..1c73641c 100644
@@ -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",
Signature · 1 line
2.11.0
#32 lore raw

Re: [Openvpn-devel] [PATCH 2/7] OpenSSL: don't use direct access to the internal of EVP_PKEY

Hi,

Quoted 101 lines · Emmanuel Deloget

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.

---
 configure.ac                 |  3 +++
 src/openvpn/openssl_compat.h | 42 ++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  6 +++---
 3 files changed, 48 insertions(+), 3 deletions(-)
configure.ac +3 -0
index 9d5e340b..a92e8142 100644
@@ -926,6 +926,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 \
src/openvpn/openssl_compat.h +42 -0
index 29a7588c..0d82cf25 100644
@@ -134,6 +134,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
src/openvpn/ssl_openssl.c +2 -2
index a082c3cd..1c73641c 100644
@@ -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

src/openvpn/ssl_openssl.c print_details(struct key_state_ssl *ks_ssl, const char *prefix) · line 1689

Quoted 10 lines
src/openvpn/ssl_openssl.c +1 -1
                 && 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",

This looks good to me - ACK.

-Steffan

#33 lore raw

PATCH 3/7 OpenSSL: don't use direct access to the internal of RSA

In reply to Emmanuel Deloget

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.

---
 configure.ac                 |  3 ++
 src/openvpn/openssl_compat.h | 84 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 24 ++++++++-----
 3 files changed, 103 insertions(+), 8 deletions(-)
configure.ac +3 -0
index a92e8142..e4c053c8 100644
@@ -929,6 +929,9 @@ 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_get0_key \
+			RSA_set0_key \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +84 -0

90 lines not on this page · raw message

src/openvpn/ssl_openssl.c +16 -8
index 1c73641c..48479c0d 100644
@@ -975,8 +975,8 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    RSA_meth_free(rsa->meth);
-    rsa->meth = NULL;
+    const RSA_METHOD *meth = RSA_get_method(rsa);
+    RSA_meth_free((RSA_METHOD *)meth);
     return 1;
 }
 
@@ -1075,8 +1075,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 +1680,16 @@ 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)
             {
-                openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
-                                 BN_num_bits(pkey->pkey.rsa->n));
+                RSA *rsa = EVP_PKEY_get0_RSA(pkey);
+                const BIGNUM *n = NULL;
+                RSA_get0_key(rsa, &n, NULL, NULL);
+                if (n != NULL)
+                {
+                    openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                     BN_num_bits(n));
+                }
             }
             else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
                      && pkey->pkey.dsa->p != NULL)
Signature · 1 line
2.11.0
#34 lore raw

Re: [Openvpn-devel] [PATCH 3/7] OpenSSL: don't use direct access to the internal of RSA

Hi,

Patch looks good in general, but some minor remarks:

Quoted 128 lines · Emmanuel Deloget

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.

---
 configure.ac                 |  3 ++
 src/openvpn/openssl_compat.h | 84 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 24 ++++++++-----
 3 files changed, 103 insertions(+), 8 deletions(-)
configure.ac +3 -0
index a92e8142..e4c053c8 100644
@@ -929,6 +929,9 @@ 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_get0_key \
+			RSA_set0_key \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +84 -0
index 0d82cf25..29cd13a4 100644
@@ -176,6 +176,90 @@ 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_METH_NEW)
 /**
  * Allocate a new RSA method object
src/openvpn/ssl_openssl.c +0 -0
index 1c73641c..48479c0d 100644

src/openvpn/ssl_openssl.c rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i · line 979

Quoted 7 lines
src/openvpn/ssl_openssl.c +2 -2
@@ -975,8 +975,8 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    RSA_meth_free(rsa->meth);
-    rsa->meth = NULL;
+    const RSA_METHOD *meth = RSA_get_method(rsa);
+    RSA_meth_free((RSA_METHOD *)meth);

Casting away const is safe here, but I'd like to make that a bit more obvious. How about renaming 'rsa_finish()' to something like 'openvpn_extkey_rsa_finish' to make clear that this function is specific for management external key. Also, add a comment to mention that 'meth' was allocated in 'tls_ctx_use_external_private_key()' and is safe to fee here.

Quoted 25 lines
src/openvpn/ssl_openssl.c +6 -4
     return 1;
 }
 
@@ -1075,8 +1075,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 +1680,16 @@ 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)
             {

src/openvpn/ssl_openssl.c print_details(struct key_state_ssl *ks_ssl, const char *prefix) · line 1692

Quoted 10 lines
src/openvpn/ssl_openssl.c +8 -2
-                openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
-                                 BN_num_bits(pkey->pkey.rsa->n));
+                RSA *rsa = EVP_PKEY_get0_RSA(pkey);
+                const BIGNUM *n = NULL;
+                RSA_get0_key(rsa, &n, NULL, NULL);
+                if (n != NULL)
+                {
+                    openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                     BN_num_bits(n));
+                }

This would be somewhat nicer to partly implement in an RSA_bits() in openssl_compat.h (mimicing OpenSSL 1.1's RSA_bits()).

-Steffan

#35 lore raw

PATCH 4/7 OpenSSL: don't use direct access to the internal of DSA

In reply to Emmanuel Deloget

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.

---
 configure.ac                 |  1 +
 src/openvpn/openssl_compat.h | 28 ++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 13 +++++++++----
 3 files changed, 38 insertions(+), 4 deletions(-)
configure.ac +1 -0
index e4c053c8..d2dc1ffd 100644
@@ -932,6 +932,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			RSA_set_flags \
 			RSA_get0_key \
 			RSA_set0_key \
+			DSA_get0_pqg \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +28 -0
index 29cd13a4..fdfc4a27 100644
@@ -260,6 +260,34 @@ RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
 }
 #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_RSA_METH_NEW)
 /**
  * Allocate a new RSA method object
src/openvpn/ssl_openssl.c +9 -4
index 48479c0d..242ab397 100644
@@ -1691,11 +1691,16 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
                                      BN_num_bits(n));
                 }
             }
-            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)
             {
-                openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
-                                 BN_num_bits(pkey->pkey.dsa->p));
+                DSA *dsa = EVP_PKEY_get0_DSA(pkey);
+                const BIGNUM *p = NULL;
+                DSA_get0_pqg(dsa, &p, NULL, NULL);
+                if (p != NULL)
+                {
+                    openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
+                                     BN_num_bits(p));
+                }
             }
             EVP_PKEY_free(pkey);
         }
Signature · 1 line
2.11.0
#36 lore raw

Re: [Openvpn-devel] [PATCH 4/7] OpenSSL: don't use direct access to the internal of DSA

Hi,

Quoted 77 lines · Emmanuel Deloget

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.

---
 configure.ac                 |  1 +
 src/openvpn/openssl_compat.h | 28 ++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 13 +++++++++----
 3 files changed, 38 insertions(+), 4 deletions(-)
configure.ac +1 -0
index e4c053c8..d2dc1ffd 100644
@@ -932,6 +932,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			RSA_set_flags \
 			RSA_get0_key \
 			RSA_set0_key \
+			DSA_get0_pqg \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +28 -0
index 29cd13a4..fdfc4a27 100644
@@ -260,6 +260,34 @@ RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
 }
 #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_RSA_METH_NEW)
 /**
  * Allocate a new RSA method object
src/openvpn/ssl_openssl.c +1 -2
index 48479c0d..242ab397 100644
@@ -1691,11 +1691,16 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
                                      BN_num_bits(n));
                 }
             }
-            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)
             {

src/openvpn/ssl_openssl.c print_details(struct key_state_ssl *ks_ssl, const char *prefix) · line 1703

Quoted 10 lines
src/openvpn/ssl_openssl.c +8 -2
-                openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
-                                 BN_num_bits(pkey->pkey.dsa->p));
+                DSA *dsa = EVP_PKEY_get0_DSA(pkey);
+                const BIGNUM *p = NULL;
+                DSA_get0_pqg(dsa, &p, NULL, NULL);
+                if (p != NULL)
+                {
+                    openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
+                                     BN_num_bits(p));
+                }

Similar to 3/7: a DSA_bits() in openssl_compat.h is somewhat nicer.

-Steffan

#37 lore raw

PATCH 5/7 OpenSSL: don't use direct access to the internal of EVP_MD_CTX

In reply to Emmanuel Deloget

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.

---
 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 | 50 ++++++++++++++++++++++++++++
 src/openvpn/openvpn.h        |  2 +-
 src/openvpn/push.c           | 11 ++++---
 9 files changed, 150 insertions(+), 52 deletions(-)
configure.ac +3 -0
index d2dc1ffd..9c7074d1 100644
@@ -920,6 +920,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 \
src/openvpn/crypto_backend.h +14 -0
index 9b113d7b..8f03e2ba 100644
@@ -508,6 +508,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
src/openvpn/crypto_mbedtls.c +12 -0
index 942684ce..d6741523 100644
@@ -766,6 +766,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)
src/openvpn/crypto_openssl.c +15 -3
index 881a2d13..fd599f40 100644
@@ -42,6 +42,7 @@
 #include "integer.h"
 #include "crypto.h"
 #include "crypto_backend.h"
+#include "openssl_compat.h"
 
 #include <openssl/des.h>
 #include <openssl/err.h>
@@ -844,13 +845,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);
 }
@@ -858,7 +870,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
src/openvpn/httpdigest.c +40 -38

107 lines not on this page · raw message

src/openvpn/misc.c +8 -6
index 68d06876..5a997750 100644
@@ -1388,7 +1388,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);
@@ -1396,11 +1396,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
src/openvpn/openssl_compat.h +50 -0

56 lines not on this page · raw message

src/openvpn/openvpn.h +1 -1
index f8682d17..21899bb9 100644
@@ -473,7 +473,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;
src/openvpn/push.c +7 -4
index bcef0ef4..908b650f 100644
@@ -724,7 +724,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)
@@ -738,14 +739,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;
Signature · 1 line
2.11.0
#38 lore raw

PATCH 6/7 OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX

In reply to Emmanuel Deloget

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.

---
 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(-)
configure.ac +2 -0
index 9c7074d1..8a9a3ff3 100644
@@ -920,6 +920,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 \
src/openvpn/crypto.c +2 -2
index 50e6a734..893879cf 100644
@@ -830,7 +830,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);
 
@@ -879,7 +879,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)
src/openvpn/crypto_backend.h +14 -0
index 8f03e2ba..3a911a47 100644
@@ -301,6 +301,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
src/openvpn/crypto_mbedtls.c +13 -0
index d6741523..4d38aadc 100644
@@ -509,6 +509,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,
src/openvpn/crypto_openssl.c +13 -2
index fd599f40..0644f1c3 100644
@@ -651,6 +651,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,
@@ -658,8 +671,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))
     {
src/openvpn/openssl_compat.h +28 -0
index 8305ec5b..d1be9d78 100644
@@ -96,6 +96,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
Signature · 1 line
2.11.0
#39 lore raw

PATCH 7/7 OpenSSL: don't use direct access to the internal of HMAC_CTX

In reply to Emmanuel Deloget

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.

---
 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(-)
configure.ac +4 -0
index 8a9a3ff3..7875c4fb 100644
@@ -922,6 +922,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 \
src/openvpn/crypto.c +2 -2
index 893879cf..a80c3f7f 100644
@@ -854,7 +854,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,
@@ -885,7 +885,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;
src/openvpn/crypto_backend.h +14 -0
index 3a911a47..3dc75ab9 100644
@@ -584,6 +584,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.
  *
src/openvpn/crypto_mbedtls.c +15 -0
index 4d38aadc..f0698f61 100644
@@ -841,6 +841,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)
src/openvpn/crypto_openssl.c +14 -3
index 0644f1c3..b64f7f04 100644
@@ -911,6 +911,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,
@@ -918,8 +931,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);
 
@@ -930,7 +941,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
src/openvpn/ntlm.c +6 -6
index 0c436812..4a4e8b9b 100644
@@ -86,13 +86,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
src/openvpn/openssl_compat.h +65 -0

71 lines not on this page · raw message

src/openvpn/ssl.c +20 -18
index 3d5e8241..55cc457d 100644
@@ -1607,8 +1607,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;
 
@@ -1617,8 +1617,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));
@@ -1626,36 +1626,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));
Signature · 1 line
2.11.0
#40 lore raw

Re: [Openvpn-devel] [PATCH 1/7] OpenSSL: don't use direct access to the internal of X509

In reply to Emmanuel Deloget

Hi,

Quoted 12 lines · Emmanuel Deloget

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).

Quoted 6 lines

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.

Very nice that you found a way out of this!

Quoted 95 lines

Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library.

---
 configure.ac                     |  1 +
 src/openvpn/openssl_compat.h     | 15 ++++++++++
 src/openvpn/ssl_openssl.c        |  3 +-
 src/openvpn/ssl_verify_openssl.c | 64 ++++++++++++++++++++++++++++++++++------
 4 files changed, 73 insertions(+), 10 deletions(-)
configure.ac +1 -0
index 7d3fce5b..9d5e340b 100644
@@ -922,6 +922,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 \
src/openvpn/openssl_compat.h +15 -0
index 92f014d5..29a7588c 100644
@@ -74,6 +74,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
src/openvpn/ssl_openssl.c +2 -1
index 645ccf51..a082c3cd 100644
@@ -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 */
src/openvpn/ssl_verify_openssl.c +7 -5
index 9b1533bc..4785f314 100644
@@ -294,18 +294,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;
 }
 
@@ -578,13 +580,57 @@ x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
     }

src/openvpn/ssl_verify_openssl.c x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) · line 588

Quoted 10 lines
src/openvpn/ssl_verify_openssl.c +6 -2
     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 wierd thing that
+         * prevent it to take a const argument
+         */
+        result_t result = X509_check_purpose((X509 *)peer_cert, X509_PURPOSE_SSL_CLIENT, 0) ?
+	       SUCCESS : FAILURE;

Instead of casting away const, I think we should remove the 'const' qualifier from the function argument. The caller has a non-const peer_cert anyway, and casting away const should really be avoided.

Quoted 5 lines
src/openvpn/ssl_verify_openssl.c +5 -0
+        /*
+         * 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
+         */

src/openvpn/ssl_verify_openssl.c x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) · line 604

Quoted 10 lines
src/openvpn/ssl_verify_openssl.c +10 -0
+        if (result == FAILURE)
+        {
+            ASN1_BIT_STRING *ns;
+            ns = X509_get_ext_d2i((X509 *)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)");
+            }

This seems to introduce a memory leak: ns should be free'd using ASN1_BIT_STRING_free().

Quoted 25 lines
src/openvpn/ssl_verify_openssl.c +19 -2
+        }
+        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 wierd thing that
+         * prevent it to take a const argument
+         */
+        result_t result = X509_check_purpose((X509 *)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((X509 *)peer_cert, NID_netscape_cert_type, NULL, NULL);
+            result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_SERVER)) ? SUCCESS : FAILURE;

src/openvpn/ssl_verify_openssl.c x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) · line 636

Quoted 10 lines
src/openvpn/ssl_verify_openssl.c +7 -0
+            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)");
+            }
+        }
+        return result;
     }
 
     return FAILURE;

Could you send a follow-up patch with these issues fixed?

Thanks,
-Steffan

#41 lore raw

Re: [Openvpn-devel] OpenSSL 1.1 patch set - status?

In reply to Emmanuel Deloget

Hi,

Quoted 6 lines · Emmanuel Deloget
Quoted 3 lines

I'm wondering where this got stuck - are you waiting for us to move forward (like, missing review of parts of the patch set), or are we waiting for you, and you've been busy?

Problem is that I'm working in a more-than-full-time manner on way-too-many-other subjects :)

Thanks for quickly sending us the current patch set. Now it's on us again.

(And yes, we fully understand the "too many projects, too many complaining customers, angry wife as well, and too little time" thing :) )

Over to Steffan now - I'm so happy that I do not have to understand OpenSSL code... ;-)

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#42 lore raw

Re: [Openvpn-devel] OpenSSL 1.1 patch set - status?

Hi Gert,

Quoted 12 lines · Gert Doering

Hi,

Quoted 6 lines · Emmanuel Deloget
Quoted 3 lines

I'm wondering where this got stuck - are you waiting for us to move forward (like, missing review of parts of the patch set), or are we waiting for you, and you've been busy?

Problem is that I'm working in a more-than-full-time manner on way-too-many-other subjects :)

Thanks for quickly sending us the current patch set. Now it's on us again.

​If there is anything bad, please tell me - I should be able to do another round if needed :)​

Quoted 5 lines

(And yes, we fully understand the "too many projects, too many complaining customers, angry wife as well, and too little time" thing :) )

​Yeah. It seems that "somebody" limited the day length to a small value that fit on a 5 bit word. I'm wondering if this "person" was told about uint32_t...​

Quoted 4 lines

Over to Steffan now - I'm so happy that I do not have to understand OpenSSL code... ;-)

​Good thing is : there is nothing complex in the changes I made. I'm pretty sure you'll be able to understand both the changes and what the original code does :)​

Quoted 3 lines

gert

​BR,

-- Emmanuel Deloget​

#43 lore raw

Re: [Openvpn-devel] OpenSSL 1.1 patch set - status?

Hi,

Quoted 22 lines · Emmanuel Deloget
Quoted 10 lines · Gert Doering
Quoted 6 lines · Emmanuel Deloget
Quoted 3 lines

I'm wondering where this got stuck - are you waiting for us to move forward (like, missing review of parts of the patch set), or are we waiting for you, and you've been busy?

Problem is that I'm working in a more-than-full-time manner on way-too-many-other subjects :)

Thanks for quickly sending us the current patch set. Now it's on us again.

If there is anything bad, please tell me - I should be able to do another round if needed :)

Quoted 2 lines

(And yes, we fully understand the "too many projects, too many complaining customers, angry wife as well, and too little time" thing :) )

Yeah. It seems that "somebody" limited the day length to a small value that fit on a 5 bit word. I'm wondering if this "person" was told about uint32_t...

Quoted 6 lines
Quoted 2 lines

Over to Steffan now - I'm so happy that I do not have to understand OpenSSL code... ;-)

Good thing is : there is nothing complex in the changes I made. I'm pretty sure you'll be able to understand both the changes and what the original code does :)

This is probably the most polite bump mail I've ever seen :-p

Just so you know: I haven't forgotten about these - they are confronting me with my back log each time I open my mailbox... I'll get to it at some point, but in the mean time (as always) other reviewers are of course welcome to look at them too!

-Steffan

#44 lore raw

RFC PATCH 6/15 OpenSSL: don't use direct access to the internal of EVP_PKEY

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

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.

---
 configure.ac                 |  2 ++
 src/openvpn/openssl_compat.h | 28 ++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  6 +++---
 3 files changed, 33 insertions(+), 3 deletions(-)
configure.ac +2 -0
index c41db3effbb26318be4f44009a5055e808b89b56..4815b8928dc04239d5019d246fd2cb13cbc99d52 100644
@@ -906,6 +906,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			X509_STORE_get0_objects \
 			X509_OBJECT_free \
 			X509_OBJECT_get_type \
+			EVP_PKEY_get0_RSA \
+			EVP_PKEY_get0_DSA \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +28 -0
index 6a89b91b05e0370a50ac5a1cae20ae659e6c7634..5062b705cccdff7c6b8a248be6819d3f54f64133 100644
@@ -134,6 +134,34 @@ 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_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
src/openvpn/ssl_openssl.c +3 -3
index b683961d9e4e79b9ee04cfa7ecd1b377ade9651b..dbeb868ebe89f8c18a7b89afd797c3e42dda1503 100644
@@ -1075,7 +1075,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);
@@ -1680,13 +1680,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",
Signature · 1 line
2.7.4
#45 lore raw

RFC PATCH 7/15 OpenSSL: don't use direct access to the internal of RSA

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

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.

---
 configure.ac                 |  3 ++
 src/openvpn/openssl_compat.h | 84 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 25 ++++++++-----
 3 files changed, 104 insertions(+), 8 deletions(-)
configure.ac +3 -0
index 4815b8928dc04239d5019d246fd2cb13cbc99d52..d2f9eb5aae7351fb76c94b4cccd7e0a7cd50ddee 100644
@@ -908,6 +908,9 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			X509_OBJECT_get_type \
 			EVP_PKEY_get0_RSA \
 			EVP_PKEY_get0_DSA \
+			RSA_set_flags \
+			RSA_get0_key \
+			RSA_set0_key \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +84 -0

90 lines not on this page · raw message

src/openvpn/ssl_openssl.c +17 -8
index dbeb868ebe89f8c18a7b89afd797c3e42dda1503..416ba0c5620a013d97db455c719a8fef60128b88 100644
@@ -978,8 +978,9 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    RSA_meth_free(rsa->meth);
-    rsa->meth = NULL;
+    RSA_METHOD *meth = (RSA_METHOD *)RSA_get_method(rsa);
+    RSA_meth_free(meth);
+    RSA_set_method(rsa, NULL);
     return 1;
 }
 
@@ -1078,8 +1079,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;
@@ -1680,11 +1684,16 @@ 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)
             {
-                openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
-                                 BN_num_bits(pkey->pkey.rsa->n));
+                RSA *rsa = EVP_PKEY_get0_RSA(pkey);
+                const BIGNUM *n = NULL;
+                RSA_get0_key(rsa, &n, NULL, NULL);
+                if (n != NULL)
+                {
+                    openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                     BN_num_bits(n));
+                }
             }
             else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
                      && pkey->pkey.dsa->p != NULL)
Signature · 1 line
2.7.4
#46 lore raw

RFC PATCH 8/15 OpenSSL: don't use direct access to the internal of DSA

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

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.

---
 configure.ac                 |  1 +
 src/openvpn/openssl_compat.h | 28 ++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 13 +++++++++----
 3 files changed, 38 insertions(+), 4 deletions(-)
configure.ac +1 -0
index d2f9eb5aae7351fb76c94b4cccd7e0a7cd50ddee..3f59ba051692fa40304a203355c82812ca0962e8 100644
@@ -911,6 +911,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			RSA_set_flags \
 			RSA_get0_key \
 			RSA_set0_key \
+			DSA_get0_pqg \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +28 -0
index 1e6f062b805022a3555204fe95cc0ef428b2bc54..d4f16e4a2ce485d80ad82ca1ef677cf6c4c4ebf7 100644
@@ -246,6 +246,34 @@ RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
 }
 #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_RSA_METH_NEW)
 /**
  * Allocate a new RSA method object
src/openvpn/ssl_openssl.c +9 -4
index 416ba0c5620a013d97db455c719a8fef60128b88..a9ae20f45fe60d35af97e7d14bfd2332f9360c30 100644
@@ -1695,11 +1695,16 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
                                      BN_num_bits(n));
                 }
             }
-            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)
             {
-                openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
-                                 BN_num_bits(pkey->pkey.dsa->p));
+                DSA *dsa = EVP_PKEY_get0_DSA(pkey);
+                const BIGNUM *p = NULL;
+                DSA_get0_pqg(dsa, &p, NULL, NULL);
+                if (p != NULL)
+                {
+                    openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA",
+                                     BN_num_bits(p));
+                }
             }
             EVP_PKEY_free(pkey);
         }
Signature · 1 line
2.7.4
#47 lore raw

RFC PATCH 9/15 OpenSSL: don't use direct access to the internal of X509_STORE_CTX

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_STORE_CTX. We have to use the defined functions to do so.

Fortunately, these functions have existed since the dawn of time so we don't have any compatibility issue here.

---
 src/openvpn/ssl_verify_openssl.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)
src/openvpn/ssl_verify_openssl.c +10 -9
index edc709b89eb05bca895639dde606b29f8e1f7024..5bdd1e3609c4a2693e16c0835a9e5c39babd5ff8 100644
@@ -62,14 +62,15 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
     session = (struct tls_session *) SSL_get_ex_data(ssl, mydata_index);
     ASSERT(session);
 
-    struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc);
-    cert_hash_remember(session, ctx->error_depth, &cert_hash);
+    X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
+    struct buffer cert_hash = x509_get_sha256_fingerprint(current_cert, &gc);
+    cert_hash_remember(session, X509_STORE_CTX_get_error_depth(ctx), &cert_hash);
 
     /* did peer present cert which was signed by our root cert? */
     if (!preverify_ok)
     {
         /* get the X509 name */
-        char *subject = x509_get_subject(ctx->current_cert, &gc);
+        char *subject = x509_get_subject(current_cert, &gc);
 
         if (!subject)
         {
@@ -77,11 +78,11 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
         }
 
         /* Log and ignore missing CRL errors */
-        if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL)
+        if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL)
         {
             msg(D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s",
-                ctx->error_depth,
-                X509_verify_cert_error_string(ctx->error),
+                X509_STORE_CTX_get_error_depth(ctx),
+                X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)),
                 subject);
             ret = 1;
             goto cleanup;
@@ -89,8 +90,8 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
 
         /* Remote site specified a certificate, but it's not correct */
         msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s",
-            ctx->error_depth,
-            X509_verify_cert_error_string(ctx->error),
+            X509_STORE_CTX_get_error_depth(ctx),
+            X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)),
             subject);
 
         ERR_clear_error();
@@ -99,7 +100,7 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
         goto cleanup;
     }
 
-    if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth))
+    if (SUCCESS != verify_cert(session, current_cert, X509_STORE_CTX_get_error_depth(ctx)))
     {
         goto cleanup;
     }
Signature · 1 line
2.7.4
#48 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 09/15] OpenSSL: don't use direct access to the internal of X509_STORE_CTX

Hi,

Quoted 65 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_STORE_CTX. We have to use the defined functions to do so.

Fortunately, these functions have existed since the dawn of time so we don't have any compatibility issue here.

---
 src/openvpn/ssl_verify_openssl.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)
src/openvpn/ssl_verify_openssl.c +9 -8
index edc709b89eb05bca895639dde606b29f8e1f7024..5bdd1e3609c4a2693e16c0835a9e5c39babd5ff8 100644
@@ -62,14 +62,15 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
     session = (struct tls_session *) SSL_get_ex_data(ssl, mydata_index);
     ASSERT(session);
 
-    struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc);
-    cert_hash_remember(session, ctx->error_depth, &cert_hash);
+    X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
+    struct buffer cert_hash = x509_get_sha256_fingerprint(current_cert, &gc);
+    cert_hash_remember(session, X509_STORE_CTX_get_error_depth(ctx), &cert_hash);
 
     /* did peer present cert which was signed by our root cert? */
     if (!preverify_ok)
     {
         /* get the X509 name */
-        char *subject = x509_get_subject(ctx->current_cert, &gc);
+        char *subject = x509_get_subject(current_cert, &gc);
 
         if (!subject)
         {
@@ -77,11 +78,11 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
         }
 
         /* Log and ignore missing CRL errors */
-        if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL)
+        if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL)
         {
             msg(D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s",
-                ctx->error_depth,
-                X509_verify_cert_error_string(ctx->error),
+                X509_STORE_CTX_get_error_depth(ctx),
+                X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)),
                 subject);
             ret = 1;
             goto cleanup;
@@ -89,8 +90,8 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
 
         /* Remote site specified a certificate, but it's not correct */
         msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s",
-            ctx->error_depth,
-            X509_verify_cert_error_string(ctx->error),
+            X509_STORE_CTX_get_error_depth(ctx),
+            X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)),
             subject);
 
         ERR_clear_error();

src/openvpn/ssl_verify_openssl.c verify_callback(int preverify_ok, X509_STORE_CTX *ctx) · line 106

Quoted 8 lines
src/openvpn/ssl_verify_openssl.c +1 -1
@@ -99,7 +100,7 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
         goto cleanup;
     }
 
-    if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth))
+    if (SUCCESS != verify_cert(session, current_cert, X509_STORE_CTX_get_error_depth(ctx)))
     {
         goto cleanup;
     }

ACK. Changes look good and tested against OpenSSL 0.9.8, 1.0.0, 1.0.1 and 1.0.2.

-Steffan

#49 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 09/15] OpenSSL: don't use direct access to the internal of X509_STORE_CTX

Steffan Karger <[email protected]...> on Tue, 2017/02/21 22:30:

Quoted 2 lines

ACK. Changes look good and tested against OpenSSL 0.9.8, 1.0.0, 1.0.1 and 1.0.2.

You answered to a patch in the middle of a series. Does this ACK apply to the complete series or just this patch?

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#50 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 09/15] OpenSSL: don't use direct access to the internal of X509_STORE_CTX

Quoted 6 lines · Christian Hesse

Steffan Karger <[email protected]...> on Tue, 2017/02/21 22:30:

Quoted 2 lines

ACK. Changes look good and tested against OpenSSL 0.9.8, 1.0.0, 1.0.1 and 1.0.2.

You answered to a patch in the middle of a series. Does this ACK apply to the complete series or just this patch?

Just this one. Not much brains left last night, so I only reviewed this rather simple and independent patch out of the series :)

-Steffan

#51 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of X509_STORE_CTX

In reply to [email protected]...

Your patch has been applied to the master and release/2.4 branch.

commit 88046ad9e8e333259ae6fb4a295a9931a1a0e47f (master) commit 58efba5013f6dae4136cc038af9ffd23796cbc0d (release/2.4)

Author: Emmanuel Deloget
Date:   Fri Feb 17 23:00:48 2017 +0100
     OpenSSL: don't use direct access to the internal of X509_STORE_CTX

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <11477a0a3cf636572c84e0110a6f1b726bc60c2c.1487368114.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14085.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#52 lore raw

RFC PATCH 10/15 OpenSSL: don't use direct access to the internal of EVP_MD_CTX

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

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.

---
 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 | 50 ++++++++++++++++++++++++++++
 src/openvpn/openvpn.h        |  2 +-
 src/openvpn/push.c           | 11 ++++---
 9 files changed, 150 insertions(+), 52 deletions(-)
configure.ac +3 -0
index 3f59ba051692fa40304a203355c82812ca0962e8..c7e9df5e3ef3f3740f2db79fef6d5c1587c47800 100644
@@ -900,6 +900,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 \
src/openvpn/crypto_backend.h +14 -0
index 2c79baa15c2021d679e1bddf269f4662e1686e5f..9b35cdaaf5a5f6c9f2b6af766fbb1b439db4c58f 100644
@@ -502,6 +502,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
src/openvpn/crypto_mbedtls.c +12 -0
index 942684ce03f62761bee538ec1abf53e958218ad1..d67415233cd4f7d7b75a43ac30ad864458b75b47 100644
@@ -766,6 +766,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)
src/openvpn/crypto_openssl.c +15 -3
index e4557156106ae099ea07979a3dcc656995659502..da3abfb7ef30fe23d7b47cd398c5cbdf61a9718b 100644
@@ -42,6 +42,7 @@
 #include "integer.h"
 #include "crypto.h"
 #include "crypto_backend.h"
+#include "openssl_compat.h"
 
 #include <openssl/des.h>
 #include <openssl/err.h>
@@ -846,13 +847,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);
 }
@@ -860,7 +872,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
src/openvpn/httpdigest.c +40 -38

107 lines not on this page · raw message

src/openvpn/misc.c +8 -6
index a2f45b61c1aa1dd279fddaf5031fc2bc9aa82145..0c422dd128a6f01f04b0943f86ed4648c4cb2576 100644
@@ -1439,7 +1439,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);
@@ -1447,11 +1447,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
src/openvpn/openssl_compat.h +50 -0

56 lines not on this page · raw message

src/openvpn/openvpn.h +1 -1
index 893296edc539800db6463b5861e6f7c83cbac115..e6cea506e37f987c8dffcef33033556d6f2c37ee 100644
@@ -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;
src/openvpn/push.c +7 -4
index 8c3104ed7690cdf24463c1d610cecf955d744cf4..7479f7c2f925dd2f74011c73e283a4421ed60bf6 100644
@@ -722,7 +722,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)
@@ -736,14 +737,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;
Signature · 1 line
2.7.4
#53 lore raw

RFC PATCH 11/15 OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

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.

---
 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(-)
configure.ac +2 -0
index c7e9df5e3ef3f3740f2db79fef6d5c1587c47800..ff9b00447fce07d9f1c408a00ea2fafe8c786cb7 100644
@@ -900,6 +900,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 \
src/openvpn/crypto.c +2 -2
index 909f725300fce7fb8986f4afb706a97e968ff195..4ba344d1f6185afcc2205a7ce501607a2b5fff87 100644
@@ -820,7 +820,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);
 
@@ -869,7 +869,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)
src/openvpn/crypto_backend.h +14 -0
index 9b35cdaaf5a5f6c9f2b6af766fbb1b439db4c58f..04876bffe9c9de0afd40ff58bcba5dce3eab18ca 100644
@@ -295,6 +295,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
src/openvpn/crypto_mbedtls.c +13 -0
index d67415233cd4f7d7b75a43ac30ad864458b75b47..4d38aadcdbd3a3158cd8a1da5f335e80e0c3a27d 100644
@@ -509,6 +509,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,
src/openvpn/crypto_openssl.c +13 -2
index da3abfb7ef30fe23d7b47cd398c5cbdf61a9718b..82da531f353a2430dbc2c4396aff459844af0cc2 100644
@@ -653,6 +653,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,
@@ -660,8 +673,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))
     {
src/openvpn/openssl_compat.h +28 -0
index 3be0f4a5abe913e5b67115b86f840a4d107f9c56..9e3969c65bfdcf2a2453ba2196bb70a0102112bd 100644
@@ -96,6 +96,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
Signature · 1 line
2.7.4
#54 lore raw

RFC PATCH 12/15 OpenSSL: don't use direct access to the internal of HMAC_CTX

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

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.

---
 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(-)
configure.ac +4 -0
index ff9b00447fce07d9f1c408a00ea2fafe8c786cb7..b8afda2df90081b7e1a7272d019eddfc21cf7bc8 100644
@@ -902,6 +902,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 \
src/openvpn/crypto.c +2 -2
index 4ba344d1f6185afcc2205a7ce501607a2b5fff87..dd7c8d8a8113d5e8136544df325de9d39b2be2b9 100644
@@ -844,7 +844,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,
@@ -875,7 +875,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;
src/openvpn/crypto_backend.h +14 -0
index 04876bffe9c9de0afd40ff58bcba5dce3eab18ca..e5442c5f7875dad6156c21870c5c168a4c8a2929 100644
@@ -578,6 +578,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.
  *
src/openvpn/crypto_mbedtls.c +15 -0
index 4d38aadcdbd3a3158cd8a1da5f335e80e0c3a27d..f0698f61dd925f591cc39a9e931cbd7fb7a0dee0 100644
@@ -841,6 +841,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)
src/openvpn/crypto_openssl.c +14 -3
index 82da531f353a2430dbc2c4396aff459844af0cc2..2f77a9853ac484770dcd808efdf13671ade7e758 100644
@@ -913,6 +913,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,
@@ -920,8 +933,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);
 
@@ -932,7 +943,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
src/openvpn/ntlm.c +6 -6
index 0c436812ece383331fc0106e9e399fb1e660786c..4a4e8b9b034efa6a8fd752aa43f892df585f94d5 100644
@@ -86,13 +86,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
src/openvpn/openssl_compat.h +65 -0

71 lines not on this page · raw message

src/openvpn/ssl.c +20 -18
index 86450fe057f33fa10803775da69d2506687a4313..03dc80ff9e4b69184bd90dc2f3b1fe1d2718be49 100644
@@ -1614,8 +1614,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;
 
@@ -1624,8 +1624,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));
@@ -1633,36 +1633,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));
Signature · 1 line
2.7.4
#55 lore raw

RFC PATCH 13/15 OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

The old symbols do not exist anymore but the library gained new equivalent symbols (OSSL). Use them instead of the old ones

---
 src/openvpn/openssl_compat.h | 5 +++++
 src/openvpn/ssl_openssl.c    | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
src/openvpn/openssl_compat.h +5 -0
index f81ec59c134fb6da2b802e66339ecd0d67040928..054fd56cd1833bb5278eb5fd88a4c4d1908d6415 100644
@@ -601,4 +601,9 @@ RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
 }
 #endif
 
+/* SSLeay symbols have been renamed in OpenSSL 1.1 */
+#if !defined(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT)
+#define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT       RSA_F_RSA_EAY_PRIVATE_ENCRYPT
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +1 -1
index a9ae20f45fe60d35af97e7d14bfd2332f9360c30..2ff3e12b93d6f829e4b27aefc2622d52e41ce589 100644
@@ -996,7 +996,7 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 
     if (padding != RSA_PKCS1_PADDING)
     {
-        RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
+        RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
         goto done;
     }
 
Signature · 1 line
2.7.4
#56 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 13/15] OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1

Hi,

Quoted 31 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

The old symbols do not exist anymore but the library gained new equivalent symbols (OSSL). Use them instead of the old ones

---
 src/openvpn/openssl_compat.h | 5 +++++
 src/openvpn/ssl_openssl.c    | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
src/openvpn/openssl_compat.h +5 -0
index f81ec59c134fb6da2b802e66339ecd0d67040928..054fd56cd1833bb5278eb5fd88a4c4d1908d6415 100644
@@ -601,4 +601,9 @@ RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
 }
 #endif
 
+/* SSLeay symbols have been renamed in OpenSSL 1.1 */
+#if !defined(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT)
+#define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT       RSA_F_RSA_EAY_PRIVATE_ENCRYPT
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +0 -0
index a9ae20f45fe60d35af97e7d14bfd2332f9360c30..2ff3e12b93d6f829e4b27aefc2622d52e41ce589 100644

src/openvpn/ssl_openssl.c rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i · line 1002

Quoted 8 lines
src/openvpn/ssl_openssl.c +1 -1
@@ -996,7 +996,7 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 
     if (padding != RSA_PKCS1_PADDING)
     {
-        RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
+        RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
         goto done;
     }
 

ACK

-Steffan

#57 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1

In reply to [email protected]...

Your patch has been applied to the master and release/2.4 branch.

commit c828ffc648eebda20e2f9087248944fa0f52a582 (master) commit d702b2539d43a3326d76cc1764fedf237fc6744f (release/2.4)

Author: Emmanuel Deloget
Date:   Fri Feb 17 23:00:52 2017 +0100
     OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <9ce17efda7b1ed100e73554b1916c0bfa687d9d1.1487368114.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14089.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#58 lore raw

RFC PATCH 14/15 OpenSSL: check for the SSL reason, not the full error

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 changed the SSLv3 API and removed many SSL_L_SSL3_* constants. Moreover, new code might use different function code for the same error.

Thus, we extract the error reason from the error code before we compare it instead of trying to rebuild an error code that might not be correct.

The new version is compatible with OpenSSL 1.0.x as well as with older versions (starting at 0.9.8).

---
 src/openvpn/crypto_openssl.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
src/openvpn/crypto_openssl.c +1 -2
index 2f77a9853ac484770dcd808efdf13671ade7e758..23de17542bf0f4a311825373ecf8d8261fd21c73 100644
@@ -194,8 +194,7 @@ crypto_print_openssl_errors(const unsigned int flags)
     while ((err = ERR_get_error()))
     {
         /* Be more clear about frequently occurring "no shared cipher" error */
-        if (err == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL3_GET_CLIENT_HELLO,
-                            SSL_R_NO_SHARED_CIPHER))
+        if (ERR_GET_REASON(err) == SSL_R_NO_SHARED_CIPHER)
         {
             msg(D_CRYPT_ERRORS, "TLS error: The server has no TLS ciphersuites "
                 "in common with the client. Your --tls-cipher setting might be "
Signature · 1 line
2.7.4
#59 lore raw

Re: [Openvpn-devel] [RFC PATCH v1 14/15] OpenSSL: check for the SSL reason, not the full error

Hi,

Quoted 24 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

OpenSSL 1.1 changed the SSLv3 API and removed many SSL_L_SSL3_* constants. Moreover, new code might use different function code for the same error.

Thus, we extract the error reason from the error code before we compare it instead of trying to rebuild an error code that might not be correct.

The new version is compatible with OpenSSL 1.0.x as well as with older versions (starting at 0.9.8).

---
 src/openvpn/crypto_openssl.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
src/openvpn/crypto_openssl.c +0 -0
index 2f77a9853ac484770dcd808efdf13671ade7e758..23de17542bf0f4a311825373ecf8d8261fd21c73 100644

src/openvpn/crypto_openssl.c crypto_print_openssl_errors(const unsigned int flags) · line 200

Quoted 9 lines
src/openvpn/crypto_openssl.c +1 -2
@@ -194,8 +194,7 @@ crypto_print_openssl_errors(const unsigned int flags)
     while ((err = ERR_get_error()))
     {
         /* Be more clear about frequently occurring "no shared cipher" error */
-        if (err == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL3_GET_CLIENT_HELLO,
-                            SSL_R_NO_SHARED_CIPHER))
+        if (ERR_GET_REASON(err) == SSL_R_NO_SHARED_CIPHER)
         {
             msg(D_CRYPT_ERRORS, "TLS error: The server has no TLS ciphersuites "
                 "in common with the client. Your --tls-cipher setting might be "

This patch is correct even outside the context of the transition to 1.1, and can be applied immediately. ACK.

-Steffan

#60 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: check for the SSL reason, not the full error

In reply to [email protected]...

Your patch has been applied to the master and release/2.4 branch.

2.3 does not have this code, as far as I could see, so doesn't get the patch.

I can't reach sf.net right now (git.code.sf.net gives me "connection refused"), so only pushed to github and gitlab.

commit 6ddc43d1bf9b3ea3ee5db8c50d56a98fe4db4c97 (master) commit c4c359736e3ab7f06a21f1eab09e6fd4cf2bef2f (release/2.4)

Author: Emmanuel Deloget
Date:   Fri Feb 17 23:00:53 2017 +0100
     OpenSSL: check for the SSL reason, not the full error

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <0e0d4a67192b563cd07d3f06685f85e34c304142.1487368114.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14087.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#61 lore raw

RFC PATCH 15/15 OpenSSL: constify getbio() parameters

In reply to [email protected]...

From: Emmanuel Deloget <[email protected]...>

Although it is required by BIO_new() to have a non-const object, this is merely an OpenSSL interface accident. Newer versions of OpenSSL (i.e. OpenSSL 1.1) have are a bit better w.r.t. constification and changed this.

As a result, we can safely constify the BIO_METHOD parameter of getbio() (yet we still need to un-const the value when feeding it to BIO_new() for the sake of compatibility).

---
 src/openvpn/ssl_openssl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
src/openvpn/ssl_openssl.c +2 -2
index 2ff3e12b93d6f829e4b27aefc2622d52e41ce589..46942c225d72e42760cbb9fae577c87aee553508 100644
@@ -1389,10 +1389,10 @@ bio_debug_oc(const char *mode, BIO *bio)
  * through "memory BIOs".
  */
 static BIO *
-getbio(BIO_METHOD *type, const char *desc)
+getbio(const BIO_METHOD *type, const char *desc)
 {
     BIO *ret;
-    ret = BIO_new(type);
+    ret = BIO_new((BIO_METHOD *)type);
     if (!ret)
     {
         crypto_msg(M_FATAL, "Error creating %s BIO", desc);
Signature · 1 line
2.7.4
#62 lore raw
In reply to [email protected]...

Hi Emmanuel,

Quoted 56 lines · On 17-02-17 23:00, [email protected]... wrote:

From: Emmanuel Deloget <[email protected]...>

The purpose of this RFC series is to make the latest master of OpenVPN (2.5-git) linkable with OpenSSL v1.1.x. It may not be complete (I may have missed something due to my work environment, but any missing pieces will be added next week) so be a bit cautious with this. The configuration I used (--without-systemd, --without-lzo) seems to work but I must confess I did not tested much.

As you may know, the important information about the API of OpenSSL 1.1 if that it no longer provide access to the content of its objects. The structure types are now opaque and various functions have been added to fetch information from these objects.

Once theses patches have been applied, it is possible to compile OpenSSL with the latest 1.0.1 and with the latest 1.1.0. I still have to check whether compilation with 1.0.0 and 0.9.8 works. I don't try to get the OpenSSL version -- I instead decided to check for the presence of individual functions in the library and chose to reimplement the missing ones. Then I changed caller code in order to use this new interface. The net result is that OpenVPN is now using the OpenSSL 1.1 API -- regardless of the real version of OpenSSL. This might make futur changes simpler at the cost of adding more functions in the openssl_compat.h file.

Las but not least, because of the way I worked I introduced some strange artefacts (I believe they are not really relevant but some of them are weird enough to need some explaination).

* I had to introduce a function of the 1.0 API in the 1.1 code. In the 1.0 API, HMAC_CTX is populated with HMAC_CTX_init() and cleaned with HMAC_CTX_cleanup(). In 1.1 these two functions are gone and replaced with HMAC_CTX_reset(). I decided to use _reset() to implement _cleanup() but since I then could not use it for _init() (that would break an OpenVPN linked with 1.0) I created a small wrapper in 1.1 mode. So, in 1.1, HMAC_CTX_init() calls _reset() -- and everybody is happy (well, maybe not everybody).

* HMAC_CTX, EVP_MD_CTX and a few other objects cannot be allocated using malloc() so I had to change the way these object are used and initialized. I introduces a few new functions in the crypto backend to handle this.

* x509_verify_ns_cert_type() checks had to be changed. OpenSSL 1.1 does not provide any solution to access both X509::ex_flags and X509::ex_nscert so the check could not be implemented this way. The only solution I found was to use X509_check_purpose() but I'm worried that the implemented test is now far more strict.

* weirdly enough, it's no longer possible to duplicate the n parameter of a RSA public key into another RSA public key. If you do so, you also need to duplicate the e parameter. The reason is that you cannot have (n && !e) or (!n && e) (see RSA_set0_key[1]). I deciced to go the same route in my implementation and thus I needed to change the code in tls_ctx_use_external_private_key().

Quoted 5 lines

Thanks for your comprehension,

[1] https://github.com/openssl/openssl/blob/master/crypto/rsa/rsa_lib.c#L191

-- Emmanuel Deloget

Thank you very much. You approach looks good to me, and quite closely matches what I had in mind for when I would find the time to tackle this. (Which might have taken me a while, so really happy to see these patches!)

As discussed in other threads, we do want to support building on RHEL6, which is why we would prefer to be compatible with (patched) OpenSSL 0.9.8. I haven't tested anything yet, but looking at the patches this might very well just work, or otherwise just needs some minor tweaking.

Also very good that this is split up into small and independently reviewable patches. I'll start review soon.

-Steffan

#63 lore raw
Quoted 4 lines · Steffan Karger

As discussed in other threads, we do want to support building on RHEL6, which is why we would prefer to be compatible with (patched) OpenSSL 0.9.8. I haven't tested anything yet, but looking at the patches this might very well just work, or otherwise just needs some minor tweaking.

RHEL6 ships with OpenSSL 1.0.1e. We don't need anything older for git master, and I would even argue release/2.4.

RHEL5 (which goes EOL by end of next month) ships with OpenSSL 0.9.8e. So I vote for ditching 0.9.8e now.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#64 lore raw
Quoted 7 lines · David Sommerseth
Quoted 4 lines · Steffan Karger

As discussed in other threads, we do want to support building on RHEL6, which is why we would prefer to be compatible with (patched) OpenSSL 0.9.8. I haven't tested anything yet, but looking at the patches this might very well just work, or otherwise just needs some minor tweaking.

Quoted 5 lines

RHEL6 ships with OpenSSL 1.0.1e. We don't need anything older for git master, and I would even argue release/2.4.

RHEL5 (which goes EOL by end of next month) ships with OpenSSL 0.9.8e. So I vote for ditching 0.9.8e now.

Oh, very good. I messed up the versions again...

The other big long-term-support distro, SLES, does still ship and support 0.9.8 in SELS11 until 2019 (2022 for extended support), but can be updated to 1.0.1.

As far as I'm concerned, that is enough reason to only support OpenSSL 1.0.1+ for OpenVPN 2.4 (and newer).

-Steffan

#65 lore raw
In reply to Steffan Karger

Hello,

Quoted 8 lines · Steffan Karger

Hi Emmanuel,

Thank you very much. You approach looks good to me, and quite closely matches what I had in mind for when I would find the time to tackle this. (Which might have taken me a while, so really happy to see these patches!)

Thanks Steffan,

Quoted 4 lines

As discussed in other threads, we do want to support building on RHEL6, which is why we would prefer to be compatible with (patched) OpenSSL 0.9.8. I haven't tested anything yet, but looking at the patches this might very well just work, or otherwise just needs some minor tweaking.

I haven't tested compilation with 0.9.8 but unless some massive changes in the interface occured, this should not be a problem. I'd do that at the beginning of next week.

Quoted 4 lines

Also very good that this is split up into small and independently reviewable patches. I'll start review soon.

-Steffan

For the record, most of the patches deal with changing how the code access to one selected OpenSSL type. I hope it will ease review -- in the sense that people who are accustomed to the code might be able to see if something is missing.

BR,

-- Emmanuel Deloget

#66 lore raw
In reply to Steffan Karger

Hi,

Quoted 4 lines · Steffan Karger

Thank you very much. You approach looks good to me, and quite closely matches what I had in mind for when I would find the time to tackle this. (Which might have taken me a while, so really happy to see these patches!)

[..]

Quoted 2 lines

Also very good that this is split up into small and independently reviewable patches. I'll start review soon.

While Steffan is our resident expert on nasty crypto libraries, I just want to echo the sentiment - having these "chunks" tackle one API function at a time, they are easily testable, and in case something explodes, it's much easier to bisect to find the problematic one.

Now back to being a commit slave for Steffan's ACKs :-) (I do not know the APIs well enough to properly comment on the changes, I can only run tests...)

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#67 lore raw

Hello,

Quoted 11 lines · Gert Doering

Hi,

Quoted 4 lines · Steffan Karger

Thank you very much. You approach looks good to me, and quite closely matches what I had in mind for when I would find the time to tackle this. (Which might have taken me a while, so really happy to see these patches!)

[..]

Quoted 2 lines

Also very good that this is split up into small and independently reviewable patches. I'll start review soon.

Quoted 8 lines

While Steffan is our resident expert on nasty crypto libraries, I just want to echo the sentiment - having these "chunks" tackle one API function at a time, they are easily testable, and in case something explodes, it's much easier to bisect to find the problematic one.

Now back to being a commit slave for Steffan's ACKs :-) (I do not know the APIs well enough to properly comment on the changes, I can only run tests...)

I resumed the work this morning. So far the results are :

* 0.9.8zh --> EVP_PKEY_id() is not defined. I'm adding this to openssl_compat.h and will provide a v2 patch with the change. Once added, OpenVPN compiled successfully and was able to connect to my /2.3 server.

* 1.0.0t --> compile OK, connect OK

* 1.0.1u --> compile OK, connect OK

* 1.0.2.k --> compile OK, connect OK

* 1.1.0-git --> compile OK, failure to connect. I'm currently investigating this issue. I'll provide a patch as soon as I fix this (this is a bit ironic ; I may have forgotten something somewhere...).

I don't have much time to test with other OpenSSL versions but I guess you have the infrastructure that will help.

Quoted 1 line

gert

Best regards,

-- Emmanuel Deloget

#68 lore raw

Emmanuel Deloget <[email protected]...> on Mon, 2017/02/20 12:45:

Quoted 32 lines

Hello,

Quoted 11 lines · Gert Doering

Hi,

Quoted 4 lines · Steffan Karger

Thank you very much. You approach looks good to me, and quite closely matches what I had in mind for when I would find the time to tackle this. (Which might have taken me a while, so really happy to see these patches!)

[..]

Quoted 2 lines

Also very good that this is split up into small and independently reviewable patches. I'll start review soon.

Quoted 8 lines

While Steffan is our resident expert on nasty crypto libraries, I just want to echo the sentiment - having these "chunks" tackle one API function at a time, they are easily testable, and in case something explodes, it's much easier to bisect to find the problematic one.

Now back to being a commit slave for Steffan's ACKs :-) (I do not know the APIs well enough to properly comment on the changes, I can only run tests...)

I resumed the work this morning. So far the results are :

* 0.9.8zh --> EVP_PKEY_id() is not defined. I'm adding this to openssl_compat.h and will provide a v2 patch with the change. Once added, OpenVPN compiled successfully and was able to connect to my /2.3 server.

* 1.0.0t --> compile OK, connect OK

Quoted 7 lines

* 1.0.1u --> compile OK, connect OK

* 1.0.2.k --> compile OK, connect OK

* 1.1.0-git --> compile OK, failure to connect. I'm currently investigating this issue. I'll provide a patch as soon as I fix this (this is a bit ironic ; I may have forgotten something somewhere...).

That matches my findings. Built against openssl 1.1.0e (Arch Linux package openssl 1.1.0.e-1 [0]) the build itself succeeds, but 'make check' reports lots of cipher failures.

Are your patches available from a public git repository?

[0] https://www.archlinux.org/packages/staging/x86_64/openssl/

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#69 lore raw

Hi Christian,

Quoted 5 lines · Christian Hesse

That matches my findings. Built against openssl 1.1.0e (Arch Linux package openssl 1.1.0.e-1 [0]) the build itself succeeds, but 'make check' reports lots of cipher failures.

Are your patches available from a public git repository?

I will make my patches available on github ASAP.

Best regards

-- Emmanuel Deloget

Quoted 52 lines · Christian Hesse

Emmanuel Deloget <[email protected]...> on Mon, 2017/02/20 12:45:

Quoted 32 lines

Hello,

Quoted 11 lines · Gert Doering

Hi,

Quoted 4 lines · Steffan Karger

Thank you very much. You approach looks good to me, and quite closely matches what I had in mind for when I would find the time to tackle this. (Which might have taken me a while, so really happy to see these patches!)

[..]

Quoted 2 lines

Also very good that this is split up into small and independently reviewable patches. I'll start review soon.

Quoted 8 lines

While Steffan is our resident expert on nasty crypto libraries, I just want to echo the sentiment - having these "chunks" tackle one API function at a time, they are easily testable, and in case something explodes, it's much easier to bisect to find the problematic one.

Now back to being a commit slave for Steffan's ACKs :-) (I do not know the APIs well enough to properly comment on the changes, I can only run tests...)

I resumed the work this morning. So far the results are :

* 0.9.8zh --> EVP_PKEY_id() is not defined. I'm adding this to openssl_compat.h and will provide a v2 patch with the change. Once added, OpenVPN compiled successfully and was able to connect to my /2.3 server.

* 1.0.0t --> compile OK, connect OK

Quoted 7 lines

* 1.0.1u --> compile OK, connect OK

* 1.0.2.k --> compile OK, connect OK

* 1.1.0-git --> compile OK, failure to connect. I'm currently investigating this issue. I'll provide a patch as soon as I fix this (this is a bit ironic ; I may have forgotten something somewhere...).

That matches my findings. Built against openssl 1.1.0e (Arch Linux package openssl 1.1.0.e-1 [0]) the build itself succeeds, but 'make check' reports lots of cipher failures.

Are your patches available from a public git repository?

[0] https://www.archlinux.org/packages/staging/x86_64/openssl/
--
main(a){char*c=/* Schoene Gruesse */"B?IJj;MEH"
"CX:;",b;for(a/* Best regards my address: */=0;b=c[a++];)
putchar(b-1/(/* Chris cc -ox -xc - && ./x */b/42*2-3)*42);}

#70 lore raw

Hi again,

Quoted 10 lines · Emmanuel Deloget

Hi Christian,

Quoted 5 lines · Christian Hesse

That matches my findings. Built against openssl 1.1.0e (Arch Linux package openssl 1.1.0.e-1 [0]) the build itself succeeds, but 'make check' reports lots of cipher failures.

Are your patches available from a public git repository?

I will make my patches available on github ASAP.

I did as fast as I could, here they are:

https://github.com/emmanuel-deloget/openvpn/commits/openvpn-1.1

I post the PATCH V2 in a few minutes

-- Emmanuel Deloget

#71 lore raw
Quoted 10 lines · Emmanuel Deloget

Hi again,

Quoted 7 lines · Emmanuel Deloget

Hi Christian,

Quoted 4 lines · Christian Hesse

That matches my findings. Built against openssl 1.1.0e (Arch Linux package openssl 1.1.0.e-1 [0]) the build itself succeeds, but 'make check' reports lots of cipher failures.

Quoted 7 lines
Quoted 3 lines
Quoted 1 line

Are your patches available from a public git repository?

I will make my patches available on github ASAP.

I did as fast as I could, here they are:

https://github.com/emmanuel-deloget/openvpn/commits/openvpn-1.1

BTW, sorry for the branch name. I believe my fingers got stuck to a limited number of characters. This should have been openssl-1.1 but it's not too late to change it :)

#72 lore raw

Emmanuel Deloget <[email protected]...> on Mon, 2017/02/20 15:52:

Quoted 16 lines · Emmanuel Deloget
Quoted 15 lines

Hi again,

Quoted 10 lines · Emmanuel Deloget

Hi Christian,

Quoted 5 lines · Christian Hesse

That matches my findings. Built against openssl 1.1.0e (Arch Linux package openssl 1.1.0.e-1 [0]) the build itself succeeds, but 'make check' reports lots of cipher failures.

Are your patches available from a public git repository?

I will make my patches available on github ASAP.

Quoted 7 lines
Quoted 3 lines

I did as fast as I could, here they are:

https://github.com/emmanuel-deloget/openvpn/commits/openvpn-1.1

BTW, sorry for the branch name. I believe my fingers got stuck to a limited number of characters. This should have been openssl-1.1 but it's not too late to change it :)

Ah, I checked out the wrong branch. :-p

Redoing my test...

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#73 lore raw

Christian Hesse <[email protected]...> on Mon, 2017/02/20 16:02:

Quoted 23 lines

Emmanuel Deloget <[email protected]...> on Mon, 2017/02/20 15:52:

Quoted 22 lines
Quoted 19 lines · Emmanuel Deloget

Hi again,

Quoted 11 lines · Emmanuel Deloget

Hi Christian,

Quoted 5 lines · Christian Hesse

That matches my findings. Built against openssl 1.1.0e (Arch Linux package openssl 1.1.0.e-1 [0]) the build itself succeeds, but 'make check' reports lots of cipher failures.

Are your patches available from a public git repository?

I will make my patches available on github ASAP.

I did as fast as I could, here they are:

https://github.com/emmanuel-deloget/openvpn/commits/openvpn-1.1

Quoted 7 lines
Quoted 3 lines

BTW, sorry for the branch name. I believe my fingers got stuck to a limited number of characters. This should have been openssl-1.1 but it's not too late to change it :)

Ah, I checked out the wrong branch. :-p

Redoing my test...

That one looks good! Build and tested against ArchLinux package openssl 1.1.0e.

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#74 lore raw

v3 cover Add support for OpenSSL 1.1.x

This is v3 of the remaining patches for the "Add support for OpenSSL 1.1.x" series. This series is partial: only the modified patches are sent to the ML -- the other have not changed. The stats are a bit off so I don't include them in this mail.

They have been generated after a rebase from the master tree. Individual commits can be viewed at

https://github.com/emmanuel-deloget/openvpn/commits/openssl-1.1-v3

(This time, the branch name is correct :))

Changes v2 --> v3:

* RSA_METHOD (04/15): rsa_meth->name is now a dup of the name parameter; it's freed in RSA_meth_free().

* RSA (07/15): calling RSA_set_method() in rsa_finish() is both a Bad Idea and not required so it has been removed.

Changes v1 --> v2:

* EVP_PKEY (06/15): add missing function EVP_PKEY_id() for 0.9.8.

* replace patch 15/15 with a new patch to use EVP_CipherInit_ex() instead of EVP_CipherInit() when a full init is not needed.

Emmanuel Deloget (15):
[commited] OpenSSL: don't use direct access to the internal of SSL_CTX [commited] OpenSSL: don't use direct access to the internal of X509_STORE [commited] OpenSSL: don't use direct access to the internal of X509_OBJECT
OpenSSL: don't use direct access to the internal of RSA_METHOD
OpenSSL: don't use direct access to the internal of X509
OpenSSL: don't use direct access to the internal of EVP_PKEY
OpenSSL: don't use direct access to the internal of RSA
OpenSSL: don't use direct access to the internal of DSA [commited] OpenSSL: don't use direct access to the internal of X509_STORE_CTX
OpenSSL: don't use direct access to the internal of EVP_MD_CTX
OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX
OpenSSL: don't use direct access to the internal of HMAC_CTX
OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1
OpenSSL: constify getbio() parameters
OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()

Signature · 1 line
2.7.4
#75 lore raw

PATCH v3 4/15 OpenSSL: don't use direct access to the internal of RSA_METHOD

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including RSA_METHOD. 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.

---
 configure.ac                 |   9 ++
 src/openvpn/openssl_compat.h | 190 +++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  22 ++---
 3 files changed, 210 insertions(+), 11 deletions(-)
configure.ac +9 -0
index 0c55d78327597a0690fa9625e06adb8b055852b1..2406ad8d6bf10f202d3fc1e9b971bc8ec135bd4f 100644
@@ -905,6 +905,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			X509_STORE_get0_objects \
 			X509_OBJECT_free \
 			X509_OBJECT_get_type \
+			RSA_meth_new \
+			RSA_meth_free \
+			RSA_meth_set_pub_enc \
+			RSA_meth_set_pub_dec \
+			RSA_meth_set_priv_enc \
+			RSA_meth_set_priv_dec \
+			RSA_meth_set_init \
+			RSA_meth_set_finish \
+			RSA_meth_set0_app_data \
 		]
 	)
 
src/openvpn/openssl_compat.h +190 -0

200 lines not on this page · raw message

src/openvpn/ssl_openssl.c +11 -11
index bf0f643f25439f71cbfe71bf5a7e8eb834b0f012..f011e06702529ff34e91f6d0169d1adf8cc9d767 100644
@@ -978,7 +978,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    free((void *)rsa->meth);
+    RSA_meth_free(rsa->meth);
     rsa->meth = NULL;
     return 1;
 }
@@ -1053,16 +1053,16 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
     ASSERT(NULL != cert);
 
     /* allocate custom RSA method object */
-    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
-    rsa_meth->name = "OpenVPN external private key RSA Method";
-    rsa_meth->rsa_pub_enc = rsa_pub_enc;
-    rsa_meth->rsa_pub_dec = rsa_pub_dec;
-    rsa_meth->rsa_priv_enc = rsa_priv_enc;
-    rsa_meth->rsa_priv_dec = rsa_priv_dec;
-    rsa_meth->init = NULL;
-    rsa_meth->finish = rsa_finish;
-    rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
-    rsa_meth->app_data = NULL;
+    rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method",
+                            RSA_METHOD_FLAG_NO_CHECK);
+    check_malloc_return(rsa_meth);
+    RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc);
+    RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec);
+    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_set0_app_data(rsa_meth, NULL);
 
     /* allocate RSA object */
     rsa = RSA_new();
Signature · 1 line
2.7.4
#76 lore raw

Re: [Openvpn-devel] [PATCH v3 04/15] OpenSSL: don't use direct access to the internal of RSA_METHOD

Hi,

Quoted 271 lines · Emmanuel Deloget

OpenSSL 1.1 does not allow us to directly access the internal of any data type, including RSA_METHOD. 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.

---
 configure.ac                 |   9 ++
 src/openvpn/openssl_compat.h | 190 +++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  22 ++---
 3 files changed, 210 insertions(+), 11 deletions(-)
configure.ac +9 -0
index 0c55d78327597a0690fa9625e06adb8b055852b1..2406ad8d6bf10f202d3fc1e9b971bc8ec135bd4f 100644
@@ -905,6 +905,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then
 			X509_STORE_get0_objects \
 			X509_OBJECT_free \
 			X509_OBJECT_get_type \
+			RSA_meth_new \
+			RSA_meth_free \
+			RSA_meth_set_pub_enc \
+			RSA_meth_set_pub_dec \
+			RSA_meth_set_priv_enc \
+			RSA_meth_set_priv_dec \
+			RSA_meth_set_init \
+			RSA_meth_set_finish \
+			RSA_meth_set0_app_data \
 		]
 	)
 
src/openvpn/openssl_compat.h +190 -0
index 458a6adbe2b3fcd5ea63dcea6596cc24315d463c..e98e8dffc5773d73684398ae28215d4fdccac3c4 100644
@@ -41,6 +41,8 @@
 #include "config-msvc.h"
 #endif
 
+#include "buffer.h"
+
 #include <openssl/ssl.h>
 #include <openssl/x509.h>
 
@@ -117,4 +119,192 @@ X509_OBJECT_get_type(const X509_OBJECT *obj)
 }
 #endif
 
+#if !defined(HAVE_RSA_METH_NEW)
+/**
+ * Allocate a new RSA method object
+ *
+ * @param name               The object name
+ * @param flags              Configuration flags
+ * @return                   A new RSA method object
+ */
+static inline RSA_METHOD *
+RSA_meth_new(const char *name, int flags)
+{
+    RSA_METHOD *rsa_meth = NULL;
+    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
+    rsa_meth->name = string_alloc(name, NULL);
+    rsa_meth->flags = flags;
+    return rsa_meth;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_FREE)
+/**
+ * Free an existing RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ */
+static inline void
+RSA_meth_free(RSA_METHOD *meth)
+{
+    if (meth)
+    {
+        free(meth->name);
+        free(meth);
+    }
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PUB_ENC)
+/**
+ * Set the public encoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param pub_enc            the public encoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_pub_enc(RSA_METHOD *meth,
+                     int (*pub_enc) (int flen, const unsigned char *from,
+                                     unsigned char *to, RSA *rsa,
+                                     int padding))
+{
+    if (meth)
+    {
+        meth->rsa_pub_enc = pub_enc;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PUB_DEC)
+/**
+ * Set the public decoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param pub_dec            the public decoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_pub_dec(RSA_METHOD *meth,
+                     int (*pub_dec) (int flen, const unsigned char *from,
+                                     unsigned char *to, RSA *rsa,
+                                     int padding))
+{
+    if (meth)
+    {
+        meth->rsa_pub_dec = pub_dec;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PRIV_ENC)
+/**
+ * Set the private encoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param priv_enc           the private encoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_priv_enc(RSA_METHOD *meth,
+                      int (*priv_enc) (int flen, const unsigned char *from,
+                                       unsigned char *to, RSA *rsa,
+                                       int padding))
+{
+    if (meth)
+    {
+        meth->rsa_priv_enc = priv_enc;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_PRIV_DEC)
+/**
+ * Set the private decoding function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param priv_dec           the private decoding function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_priv_dec(RSA_METHOD *meth,
+                      int (*priv_dec) (int flen, const unsigned char *from,
+                                       unsigned char *to, RSA *rsa,
+                                       int padding))
+{
+    if (meth)
+    {
+        meth->rsa_priv_dec = priv_dec;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_INIT)
+/**
+ * Set the init function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param init               the init function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_init(RSA_METHOD *meth, int (*init) (RSA *rsa))
+{
+    if (meth)
+    {
+        meth->init = init;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET_FINISH)
+/**
+ * Set the finish function of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param finish             the finish function
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
+{
+    if (meth)
+    {
+        meth->finish = finish;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+#if !defined(HAVE_RSA_METH_SET0_APP_DATA)
+/**
+ * Set the application data of an RSA_METHOD object
+ *
+ * @param meth               The RSA_METHOD object
+ * @param app_data           Application data
+ * @return                   1 on success, 0 on error
+ */
+static inline int
+RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
+{
+    if (meth)
+    {
+        meth->app_data = app_data;
+        return 1;
+    }
+    return 0;
+}
+#endif
+
 #endif /* OPENSSL_COMPAT_H_ */
src/openvpn/ssl_openssl.c +4 -11
index bf0f643f25439f71cbfe71bf5a7e8eb834b0f012..f011e06702529ff34e91f6d0169d1adf8cc9d767 100644
@@ -978,7 +978,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    free((void *)rsa->meth);
+    RSA_meth_free(rsa->meth);
     rsa->meth = NULL;
     return 1;
 }
@@ -1053,16 +1053,16 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx,
     ASSERT(NULL != cert);
 
     /* allocate custom RSA method object */
-    ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
-    rsa_meth->name = "OpenVPN external private key RSA Method";
-    rsa_meth->rsa_pub_enc = rsa_pub_enc;
-    rsa_meth->rsa_pub_dec = rsa_pub_dec;
-    rsa_meth->rsa_priv_enc = rsa_priv_enc;
-    rsa_meth->rsa_priv_dec = rsa_priv_dec;
-    rsa_meth->init = NULL;
-    rsa_meth->finish = rsa_finish;
-    rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
-    rsa_meth->app_data = NULL;
+    rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method",
+                            RSA_METHOD_FLAG_NO_CHECK);
+    check_malloc_return(rsa_meth);

src/openvpn/ssl_openssl.c tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, · line 1068

Quoted 10 lines
src/openvpn/ssl_openssl.c +7 -0
+    RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc);
+    RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec);
+    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_set0_app_data(rsa_meth, NULL);
 
     /* allocate RSA object */
     rsa = RSA_new();

This looks good to me now, ACK. Thanks for following up.

-Steffan

#77 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of RSA_METHOD

In reply to Emmanuel Deloget

Your patch (v3) has been applied to the master and release/2.4 branch.

Small side note: I assume that RSA_meth_new() can fail and return NULL in OpenSSL 1.1? Because for 1.0, the "check_malloc_return(rsa_meth)" call isn't necessary, as ALLOC_OBJ_CLEAR() would call ALLOC_OBJ() and that already checks... (mentioning this here in case someone wonders and goes to the list archives).

commit 09776c5b52df13121504e07894a26d5cd1883317 (master) commit 44bac2926d6b445a7773a24bb7c295b54f4be35e (release/2.4)

Author: Emmanuel Deloget
Date:   Thu Feb 23 15:35:56 2017 +0100
     OpenSSL: don't use direct access to the internal of RSA_METHOD

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <79d89580db6fd92c059dabc4f5f4d83b72bb9d3d.1487859361.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14175.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering

#78 lore raw

Re: [Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of RSA_METHOD

Quoted 5 lines · Gert Doering

Small side note: I assume that RSA_meth_new() can fail and return NULL in OpenSSL 1.1? Because for 1.0, the "check_malloc_return(rsa_meth)" call isn't necessary, as ALLOC_OBJ_CLEAR() would call ALLOC_OBJ() and that already checks... (mentioning this here in case someone wonders and goes to the list archives).

For the archives: yes, RSA_meth_new() indeed returns NULL if it's internal malloc() call fails.

-Steffan

#79 lore raw

Re: [Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of RSA_METHOD

Hi,

Quoted 10 lines · Steffan Karger
Quoted 5 lines · Gert Doering

Small side note: I assume that RSA_meth_new() can fail and return NULL in OpenSSL 1.1? Because for 1.0, the "check_malloc_return(rsa_meth)" call isn't necessary, as ALLOC_OBJ_CLEAR() would call ALLOC_OBJ() and that already checks... (mentioning this here in case someone wonders and goes to the list archives).

For the archives: yes, RSA_meth_new() indeed returns NULL if it's internal malloc() call fails.

Yes, indeed. And that's the reason why I have a check_malloc_return() here. I'm perfectly conscious that for OpenSSL < 1.1 we're checking the pointer twice but on the other hand I would have missed the check with OpenSSL 1.1. A solution would have been to use a direct malloc()/calloc() call instead of ALLOC_OBJ_CLEAR() in the compatibility code, but that would have looked weird. Another solution would have been to encapsulate RSA_meth_new() but I don't think that would have been a good idea (yet, I might be wrong on that one). So I did this choice -- I don't like it much either but I cannot think of a better solution.

Quoted 1 line

-Steffan

Best regards,

-- Emmanuel Deloget

#80 lore raw

Re: [Openvpn-devel] [PATCH applied] Re: OpenSSL: don't use direct access to the internal of RSA_METHOD

Hi,

Quoted 1 line · Emmanuel Deloget

I don't like it much either but I cannot think of a better solution.

I haven't said that I don't *like* it :-) - I came across it when doing a "post commit sanity check" and assumed that there are good reasons. Just wanted to clarify this, in case someone else looks at the call chain and wonders.

All is well :-)

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#81 lore raw

PATCH v3 7/15 OpenSSL: don't use direct access to the internal of RSA

In reply to Emmanuel Deloget

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.

---
 configure.ac                 |  3 ++
 src/openvpn/openssl_compat.h | 84 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    | 24 ++++++++-----
 3 files changed, 103 insertions(+), 8 deletions(-)
configure.ac +3 -0
index 089aa89459803234f847579d393c2be6e17d958a..e9942e38f5675c8bcfcc30f5e5c30731a08abba2 100644
@@ -909,6 +909,9 @@ 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_get0_key \
+			RSA_set0_key \
 			RSA_meth_new \
 			RSA_meth_free \
 			RSA_meth_set_pub_enc \
src/openvpn/openssl_compat.h +84 -0

90 lines not on this page · raw message

src/openvpn/ssl_openssl.c +16 -8
index dbeb868ebe89f8c18a7b89afd797c3e42dda1503..25935b45dcac6dfc5c9d034fe14e7b29ec1cc1c3 100644
@@ -978,8 +978,8 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
 static int
 rsa_finish(RSA *rsa)
 {
-    RSA_meth_free(rsa->meth);
-    rsa->meth = NULL;
+    const RSA_METHOD *meth = RSA_get_method(rsa);
+    RSA_meth_free((RSA_METHOD *)meth);
     return 1;
 }
 
@@ -1078,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;
@@ -1680,11 +1683,16 @@ 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)
             {
-                openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
-                                 BN_num_bits(pkey->pkey.rsa->n));
+                RSA *rsa = EVP_PKEY_get0_RSA(pkey);
+                const BIGNUM *n = NULL;
+                RSA_get0_key(rsa, &n, NULL, NULL);
+                if (n != NULL)
+                {
+                    openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA",
+                                     BN_num_bits(n));
+                }
             }
             else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL
                      && pkey->pkey.dsa->p != NULL)
Signature · 1 line
2.7.4
#82 lore raw
In reply to Emmanuel Deloget

Emmanuel Deloget <[email protected]...> on Thu, 2017/02/23 15:35:

Quoted 28 lines

This is v3 of the remaining patches for the "Add support for OpenSSL 1.1.x" series. This series is partial: only the modified patches are sent to the ML -- the other have not changed. The stats are a bit off so I don't include them in this mail.

They have been generated after a rebase from the master tree. Individual commits can be viewed at

https://github.com/emmanuel-deloget/openvpn/commits/openssl-1.1-v3

(This time, the branch name is correct :))

Changes v2 --> v3:

* RSA_METHOD (04/15): rsa_meth->name is now a dup of the name parameter; it's freed in RSA_meth_free().

* RSA (07/15): calling RSA_set_method() in rsa_finish() is both a Bad Idea and not required so it has been removed.

Changes v1 --> v2:

* EVP_PKEY (06/15): add missing function EVP_PKEY_id() for 0.9.8.

* replace patch 15/15 with a new patch to use EVP_CipherInit_ex() instead of EVP_CipherInit() when a full init is not needed.

Quoted 16 lines

Emmanuel Deloget (15):
[commited] OpenSSL: don't use direct access to the internal of SSL_CTX [commited] OpenSSL: don't use direct access to the internal of X509_STORE [commited] OpenSSL: don't use direct access to the internal of X509_OBJECT
OpenSSL: don't use direct access to the internal of RSA_METHOD
OpenSSL: don't use direct access to the internal of X509
OpenSSL: don't use direct access to the internal of EVP_PKEY
OpenSSL: don't use direct access to the internal of RSA
OpenSSL: don't use direct access to the internal of DSA [commited] OpenSSL: don't use direct access to the internal of
X509_STORE_CTX OpenSSL: don't use direct access to the internal of EVP_MD_CTX OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX OpenSSL: don't use direct access to the internal of HMAC_CTX
OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1
OpenSSL: constify getbio() parameters
OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()

Built v3 against openssl 1.0.2k without issues, tests succeed and two instanced successfully established vpn connection (with server version 2.3.12 and 2.4.0).

Built against openssl 1.1.0e without issues, tests succeed. Did not test with real world connectivity, though.

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#83 lore raw

Christian Hesse <[email protected]...> on Thu, 2017/02/23 21:57:

Quoted 3 lines

Built v3 against openssl 1.0.2k without issues, tests succeed and two instanced successfully established vpn connection (with server version 2.3.12 and 2.4.0).

Just tested a server instance with ancient client (version 2.1.4). Works as well.

I will try to restart another server instance later.

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#84 lore raw

Christian Hesse <[email protected]...> on Fri, 2017/02/24 13:13:

Quoted 9 lines

Christian Hesse <[email protected]...> on Thu, 2017/02/23 21:57:

Quoted 3 lines

Built v3 against openssl 1.0.2k without issues, tests succeed and two instanced successfully established vpn connection (with server version 2.3.12 and 2.4.0).

Just tested a server instance with ancient client (version 2.1.4). Works as well.

I will try to restart another server instance later.

Just restarted the server. Here is the current client connect statistic:

      1  2.3.8
      4  2.3.12
      6  2.3.13
      7  2.3.11
     18  2.3.14
     70  2.4.0

So looks good for now. ;)

Signature · 3 lines
main(a){char*c=/*    Schoene Gruesse                         */"B?IJj;MEH"
"CX:;",b;for(a/*    Best regards             my address:    */=0;b=c[a++];)
putchar(b-1/(/*    Chris            cc -ox -xc - && ./x    */b/42*2-3)*42);}
#85 lore raw
In reply to Emmanuel Deloget

Hi,

Quoted 4 lines · Emmanuel Deloget

* 0.9.8zh --> EVP_PKEY_id() is not defined. I'm adding this to openssl_compat.h and will provide a v2 patch with the change. Once added, OpenVPN compiled successfully and was able to connect to my /2.3 server.

If possible, please do only resend the commit that got changed, not all of it (easier to keep track when Steffan starts sending reviews).

Quoted 5 lines

* 1.0.0t --> compile OK, connect OK

* 1.0.1u --> compile OK, connect OK

* 1.0.2.k --> compile OK, connect OK

Great :-)

Quoted 3 lines

* 1.1.0-git --> compile OK, failure to connect. I'm currently investigating this issue. I'll provide a patch as soon as I fix this (this is a bit ironic ; I may have forgotten something somewhere...).

Interesting. Anything useful in openvpn's logs?

Quoted 2 lines

I don't have much time to test with other OpenSSL versions but I guess you have the infrastructure that will help.

Well, *I* do not have specific "test across various OpenSSL versions" infrastructure, but compiling across our buildbot zoo gives us quite a bit of coverage... and I assume Steffan has more coverage on SSL library versions.

thanks for your work!

gert

Signature · 4 lines
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             [email protected]...
fax: +49-89-35655025                        [email protected]...
#86 lore raw

Hi,

Quoted 3 lines · Gert Doering

Interesting. Anything useful in openvpn's logs?

Mon Feb 20 11:57:56 2017 us=371715 OpenSSL: error:0607B083:digital envelope routines:EVP_CipherInit_ex:no cipher set
Mon Feb 20 11:57:56 2017 us=371746 EVP cipher init #2

I found the culprit: OpenSSL's EVP_CipherInit() changed way too much for a 3 lines function. Prior to v1.1, the code did a check on cipher parameter and cleared the EVP context only if cipher was not null. In 1.1, it clears the context unconditionnaly. Having to cope with changes in the interface is not that fun, having to cope with behavior changes is even worse :)

I'm producing an additional commit to work around that change (the proposed change does not depend on the OpenSSL version).

Quoted 11 lines
Quoted 2 lines

I don't have much time to test with other OpenSSL versions but I guess you have the infrastructure that will help.

Well, *I* do not have specific "test across various OpenSSL versions" infrastructure, but compiling across our buildbot zoo gives us quite a bit of coverage... and I assume Steffan has more coverage on SSL library versions.

thanks for your work!

gert

Well, thanks to everyone involved -- all of you have been really kind with me (for now :))

Best regards,

-- Emmanuel Deloget

#87 lore raw

v2 cover Add support for OpenSSL 1.1.x

In reply to [email protected]...

This (limited) series replaces a few patches on the v1 series, namely:

* "OpenSSL: don't use direct access to the internal of EVP_PKEY" This version replaces the previous version and adds function EVP_PKEY_id() which is present in 1.0.0 and later but not in 0.9.8.

* "OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()"

This version has been compile-tested with the following versions:

* 0.9.8zh
* 1.0.0t
* 1.0.1u
* 1.0.2k
* 1.1.0-git

Each compilation test was followed by a connection test to an OpenVPN server (v2.3). So far, everything seems to work.

Emmanuel Deloget (15):
OpenSSL: don't use direct access to the internal of SSL_CTX
OpenSSL: don't use direct access to the internal of X509_STORE
OpenSSL: don't use direct access to the internal of X509_OBJECT
OpenSSL: don't use direct access to the internal of RSA_METHOD
OpenSSL: don't use direct access to the internal of X509
OpenSSL: don't use direct access to the internal of EVP_PKEY
OpenSSL: don't use direct access to the internal of RSA
OpenSSL: don't use direct access to the internal of DSA
OpenSSL: don't use direct access to the internal of X509_STORE_CTX
OpenSSL: don't use direct access to the internal of EVP_MD_CTX
OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX
OpenSSL: don't use direct access to the internal of HMAC_CTX
OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1
OpenSSL: constify getbio() parameters
OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()

 configure.ac                     |  38 +++
 src/openvpn/crypto.c             |   8 +-
 src/openvpn/crypto_backend.h     |  42 +++
 src/openvpn/crypto_mbedtls.c     |  40 +++
 src/openvpn/crypto_openssl.c     |  54 +++-
 src/openvpn/httpdigest.c         |  78 ++---
 src/openvpn/misc.c               |  14 +-
 src/openvpn/ntlm.c               |  12 +-
 src/openvpn/openssl_compat.h     | 623 +++++++++++++++++++++++++++++++++++++++
 src/openvpn/openvpn.h            |   2 +-
 src/openvpn/push.c               |  11 +-
 src/openvpn/ssl.c                |  38 +--
 src/openvpn/ssl_openssl.c        |  94 +++---
 src/openvpn/ssl_verify_openssl.c |  55 ++--
 14 files changed, 963 insertions(+), 146 deletions(-)
 create mode 100644 src/openvpn/openssl_compat.h
Signature · 1 line
2.7.4
#88 lore raw

RFC PATCH v2 6/15 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.

---
 configure.ac                 |  3 +++
 src/openvpn/openssl_compat.h | 42 ++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/ssl_openssl.c    |  6 +++---
 3 files changed, 48 insertions(+), 3 deletions(-)
configure.ac +3 -0
index c41db3e..8d99eb3 100644
@@ -906,6 +906,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 \
src/openvpn/openssl_compat.h +42 -0

48 lines not on this page · raw message

src/openvpn/ssl_openssl.c +3 -3
index b683961..dbeb868 100644
@@ -1075,7 +1075,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);
@@ -1680,13 +1680,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",
Signature · 1 line
2.7.4
#89 lore raw

RFC PATCH v2 15/15 OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()

In reply to Emmanuel Deloget

The behavior of EVP_CipherInit() changed in OpenSSL 1.1 -- instead of clearing the context when the cipher parameter was !NULL, it now clears the context unconditionnaly. As a result, subsequent calls to the function with additional information now fails.

The bulk work is done by EVP_CipherInit_ex() which has been part of the OpenSSL interface since the dawn of time (0.9.8 already has it). Thus, the change allows us to get the old behavior back instead of relying on dirty tricks.

---
 src/openvpn/crypto_openssl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
src/openvpn/crypto_openssl.c +2 -2
index 23de175..2bca88b 100644
@@ -683,7 +683,7 @@ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
         crypto_msg(M_FATAL, "EVP set key size");
     }
 #endif
-    if (!EVP_CipherInit(ctx, NULL, key, NULL, enc))
+    if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, enc))
     {
         crypto_msg(M_FATAL, "EVP cipher init #2");
     }
@@ -736,7 +736,7 @@ cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx)
 int
 cipher_ctx_reset(EVP_CIPHER_CTX *ctx, uint8_t *iv_buf)
 {
-    return EVP_CipherInit(ctx, NULL, NULL, iv_buf, -1);
+    return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv_buf, -1);
 }
 
 int
Signature · 1 line
2.7.4
#90 lore raw

Re: [Openvpn-devel] [RFC PATCH v2 15/15] OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()

Hi,

Quoted 30 lines · Emmanuel Deloget

The behavior of EVP_CipherInit() changed in OpenSSL 1.1 -- instead of clearing the context when the cipher parameter was !NULL, it now clears the context unconditionnaly. As a result, subsequent calls to the function with additional information now fails.

The bulk work is done by EVP_CipherInit_ex() which has been part of the OpenSSL interface since the dawn of time (0.9.8 already has it). Thus, the change allows us to get the old behavior back instead of relying on dirty tricks.

---
 src/openvpn/crypto_openssl.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
src/openvpn/crypto_openssl.c +1 -1
index 23de175..2bca88b 100644
@@ -683,7 +683,7 @@ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
         crypto_msg(M_FATAL, "EVP set key size");
     }
 #endif
-    if (!EVP_CipherInit(ctx, NULL, key, NULL, enc))
+    if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, enc))
     {
         crypto_msg(M_FATAL, "EVP cipher init #2");
     }

src/openvpn/crypto_openssl.c cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx) · line 742

Quoted 8 lines
src/openvpn/crypto_openssl.c +1 -1
@@ -736,7 +736,7 @@ cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx)
 int
 cipher_ctx_reset(EVP_CIPHER_CTX *ctx, uint8_t *iv_buf)
 {
-    return EVP_CipherInit(ctx, NULL, NULL, iv_buf, -1);
+    return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv_buf, -1);
 }
 
 int

ACK

-Steffan

#91 lore raw

[Openvpn-devel] [PATCH applied] Re: OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()

In reply to Emmanuel Deloget

Your patch has been applied to the master and release/2.4 branch.

commit 8d00afae88b626c9cf14170a943b33a7ed378070 (master) commit 0fa3df510c10820d00b8f5c77a8730f90189f30d (release/2.4)

Author: Emmanuel Deloget
Date:   Mon Feb 20 15:32:34 2017 +0100
     OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit()

     Signed-off-by: Emmanuel Deloget <[email protected]...>
     Acked-by: Steffan Karger <[email protected]...>
     Message-Id: <2faff7647151d7fe362c1c5db9f97e520444d09b.1487600539.git.logout@...260...>
     URL: https://www.mail-archive.com/[email protected]/msg14120.html
     Signed-off-by: Gert Doering <[email protected]...>

--
kind regards,

Gert Doering