[Openvpn-devel,M] Change in openvpn[master]: Add support for mbedtls 3.X.Y

Message ID 597e68a0e1061309eaea6d4d130be5985914da55-HTML@gerrit.openvpn.net
State Superseded
Headers show
Series [Openvpn-devel,M] Change in openvpn[master]: Add support for mbedtls 3.X.Y | expand

Commit Message

flichtenheld (Code Review) Oct. 17, 2023, 5:05 p.m. UTC
Attention is currently required from: flichtenheld, plaisthos.

Hello plaisthos, flichtenheld,

I'd like you to do a code review.
Please visit

    http://gerrit.openvpn.net/c/openvpn/+/370?usp=email

to review the following change.


Change subject: Add support for mbedtls 3.X.Y
......................................................................

Add support for mbedtls 3.X.Y

Most struct fields in mbedtls 3 are private and now need accessor
functions. Most of it was straightforward to adapt, but for two things
there were no accessor functions yet:

 * Netscape certificate type
 * key usage (you can check key usage, but not get the raw bytes)

I decided to remove Netscape certificate type checks when using OpenVPN
with mbedtls. The key usage bytes were printed in an error message, and
I removed that part from it.

Adding the random number functions to the load private key function may
look weird, but the purpose is to make side channels for elliptic curve
operations harder to exploit.

Also bumping the minimum mbed TLS version to 2.16.12. That version is
unsupported, but it's the latest long-term support release to still be
released under the GPL.

This commit breaks compatibility for mbed TLS version 2.x.y. A
compatibility header will be added in a follow-up commit.

Change-Id: I445a93e84dc54b865b757038d22318ac427fce96
Signed-off-by: Max Fillinger <max@max-fillinger.net>
---
M configure.ac
M src/openvpn/crypto_mbedtls.c
M src/openvpn/options.c
M src/openvpn/ssl_mbedtls.c
M src/openvpn/ssl_verify_mbedtls.c
5 files changed, 95 insertions(+), 69 deletions(-)



  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/70/370/1

Patch

diff --git a/configure.ac b/configure.ac
index 266b66f..2072e8c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1016,13 +1016,13 @@ 
 #include <mbedtls/version.h>
 			]],
 			[[
-#if MBEDTLS_VERSION_NUMBER < 0x02000000 || MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER < 0x02100c00 || (MBEDTLS_VERSION_NUMBER >= 0x03000000 && MBEDTLS_VERSION_NUMBER < 0x03020100)
 #error invalid version
 #endif
 			]]
 		)],
 		[AC_MSG_RESULT([ok])],
-		[AC_MSG_ERROR([mbed TLS 2.y.z required])]
+		[AC_MSG_ERROR([mbed TLS version >= 2.16.12 or >= 3.2.1 required])]
 	)
 
 	AC_CHECK_FUNCS(
diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
index 98cac60..e85e4de 100644
--- a/src/openvpn/crypto_mbedtls.c
+++ b/src/openvpn/crypto_mbedtls.c
@@ -170,10 +170,11 @@ 
     while (*ciphers != 0)
     {
         const mbedtls_cipher_info_t *info = mbedtls_cipher_info_from_type(*ciphers);
-        if (info && !cipher_kt_insecure(info->name)
-            && (cipher_kt_mode_aead(info->name) || cipher_kt_mode_cbc(info->name)))
+        const char *name = mbedtls_cipher_info_get_name(info);
+        if (info && name
+            && (cipher_kt_mode_aead(name) || cipher_kt_mode_cbc(name)))
         {
-            print_cipher(info->name);
+            print_cipher(name);
         }
         ciphers++;
     }
@@ -184,10 +185,11 @@ 
     while (*ciphers != 0)
     {
         const mbedtls_cipher_info_t *info = mbedtls_cipher_info_from_type(*ciphers);
-        if (info && cipher_kt_insecure(info->name)
-            && (cipher_kt_mode_aead(info->name) || cipher_kt_mode_cbc(info->name)))
+        const char *name = mbedtls_cipher_info_get_name(info);
+        if (info && name && cipher_kt_insecure(name)
+            && (cipher_kt_mode_aead(name) || cipher_kt_mode_cbc(name)))
         {
-            print_cipher(info->name);
+            print_cipher(name);
         }
         ciphers++;
     }
@@ -295,7 +297,9 @@ 
     mbedtls_pem_context ctx = { 0 };
     bool ret = mbed_ok(mbedtls_pem_read_buffer(&ctx, header, footer, BPTR(&input),
                                                NULL, 0, &use_len));
-    if (ret && !buf_write(dst, ctx.buf, ctx.buflen))
+    size_t buf_size = 0;
+    const unsigned char *buf = mbedtls_pem_get_buffer(&ctx, &buf_size);
+    if (ret && !buf_write(dst, buf, buf_size))
     {
         ret = false;
         msg(M_WARN, "PEM decode error: destination buffer too small");
@@ -416,11 +420,12 @@ 
         return false;
     }
 
-    if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH)
+    int key_bytelen = mbedtls_cipher_info_get_key_bitlen(cipher)/8;
+    if (key_bytelen > MAX_CIPHER_KEY_LENGTH)
     {
         msg(D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) "
             "which is larger than " PACKAGE_NAME "'s current maximum key size "
-            "(%d bytes)", ciphername, cipher->key_bitlen/8, MAX_CIPHER_KEY_LENGTH);
+            "(%d bytes)", ciphername, key_bytelen, MAX_CIPHER_KEY_LENGTH);
         *reason = "disabled due to key size too large";
         return false;
     }
@@ -438,7 +443,7 @@ 
         return "[null-cipher]";
     }
 
-    return translate_cipher_name_to_openvpn(cipher_kt->name);
+    return translate_cipher_name_to_openvpn(mbedtls_cipher_info_get_name(cipher_kt));
 }
 
 int
@@ -451,7 +456,7 @@ 
         return 0;
     }
 
-    return cipher_kt->key_bitlen/8;
+    return mbedtls_cipher_info_get_key_bitlen(cipher_kt)/8;
 }
 
 int
@@ -463,7 +468,7 @@ 
     {
         return 0;
     }
-    return cipher_kt->iv_size;
+    return mbedtls_cipher_info_get_iv_size(cipher_kt);
 }
 
 int
@@ -474,7 +479,7 @@ 
     {
         return 0;
     }
-    return cipher_kt->block_size;
+    return mbedtls_cipher_info_get_block_size(cipher_kt);
 }
 
 int
@@ -498,7 +503,7 @@ 
 
     return !(cipher_kt_block_size(ciphername) >= 128 / 8
 #ifdef MBEDTLS_CHACHAPOLY_C
-             || cipher_kt->type == MBEDTLS_CIPHER_CHACHA20_POLY1305
+             || mbedtls_cipher_info_get_type(cipher_kt) == MBEDTLS_CIPHER_CHACHA20_POLY1305
 #endif
              );
 }
@@ -507,7 +512,7 @@ 
 cipher_kt_mode(const mbedtls_cipher_info_t *cipher_kt)
 {
     ASSERT(NULL != cipher_kt);
-    return cipher_kt->mode;
+    return mbedtls_cipher_info_get_mode(cipher_kt);
 }
 
 bool
@@ -566,9 +571,8 @@ 
     CLEAR(*ctx);
 
     const mbedtls_cipher_info_t *kt = cipher_get(ciphername);
-    int key_len = kt->key_bitlen/8;
-
     ASSERT(kt);
+    int key_len = mbedtls_cipher_info_get_key_bitlen(kt)/8;
 
     if (!mbed_ok(mbedtls_cipher_setup(ctx, kt)))
     {
@@ -581,7 +585,7 @@ 
     }
 
     /* make sure we used a big enough key */
-    ASSERT(ctx->key_bitlen <= key_len*8);
+    ASSERT(mbedtls_cipher_get_key_bitlen(ctx) <= key_len*8);
 }
 
 int
@@ -617,7 +621,7 @@ 
 {
     ASSERT(NULL != ctx);
 
-    return cipher_kt_mode(ctx->cipher_info);
+    return mbedtls_cipher_get_cipher_mode(ctx);
 }
 
 bool
@@ -652,7 +656,7 @@ 
         return 0;
     }
 
-    if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size)))
+    if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, mbedtls_cipher_get_iv_size(ctx))))
     {
         return 0;
     }
@@ -714,7 +718,7 @@ 
 {
     size_t olen = 0;
 
-    if (MBEDTLS_DECRYPT != ctx->operation)
+    if (MBEDTLS_DECRYPT != mbedtls_cipher_get_operation(ctx))
     {
         return 0;
     }
@@ -866,7 +870,7 @@ 
     {
         return 0;
     }
-    return mbedtls_md_get_size(ctx->md_info);
+    return mbedtls_md_get_size(mbedtls_md_info_from_ctx(ctx));
 }
 
 void
@@ -936,7 +940,7 @@ 
     {
         return 0;
     }
-    return mbedtls_md_get_size(ctx->md_info);
+    return mbedtls_md_get_size(mbedtls_md_info_from_ctx(ctx));
 }
 
 void
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 134bb72..7f47ba3 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -644,8 +644,10 @@ 
     "--verify-x509-name name: Accept connections only from a host with X509 subject\n"
     "                  DN name. The remote host must also pass all other tests\n"
     "                  of verification.\n"
+#ifndef ENABLE_CRYPTO_MBEDTLS
     "--ns-cert-type t: (DEPRECATED) Require that peer certificate was signed with \n"
     "                  an explicit nsCertType designation t = 'client' | 'server'.\n"
+#endif
     "--x509-track x  : Save peer X509 attribute x in environment for use by\n"
     "                  plugins and management interface.\n"
 #ifdef HAVE_EXPORT_KEYING_MATERIAL
@@ -9041,6 +9043,10 @@ 
     }
     else if (streq(p[0], "ns-cert-type") && p[1] && !p[2])
     {
+#ifdef ENABLE_CRYPTO_MBEDTLS
+        msg(msglevel, "--ns-cert-type is not available with mbedtls.");
+        goto err;
+#endif
         VERIFY_PERMISSION(OPT_P_GENERAL);
         if (streq(p[1], "server"))
         {
diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c
index 81dd906..a4ed722 100644
--- a/src/openvpn/ssl_mbedtls.c
+++ b/src/openvpn/ssl_mbedtls.c
@@ -49,15 +49,13 @@ 
 #include <mbedtls/error.h>
 #include <mbedtls/version.h>
 
-#if MBEDTLS_VERSION_NUMBER >= 0x02040000
-    #include <mbedtls/net_sockets.h>
-#else
-    #include <mbedtls/net.h>
-#endif
+#include <mbedtls/net_sockets.h>
 
 #include <mbedtls/oid.h>
 #include <mbedtls/pem.h>
 
+#include <psa/crypto.h>
+
 /**
  * Compatibility: mbedtls_ctr_drbg_update was deprecated in mbedtls 2.16 and
  * replaced with mbedtls_ctr_drbg_update_ret, which returns an error code.
@@ -108,6 +106,7 @@ 
 void
 tls_init_lib(void)
 {
+    (void)psa_crypto_init();
 }
 
 void
@@ -430,7 +429,7 @@ 
     }
 
     msg(D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " bit key",
-        (counter_type) 8 * mbedtls_mpi_size(&ctx->dhm_ctx->P));
+        (counter_type) mbedtls_dhm_get_bitlen(ctx->dhm_ctx));
 }
 
 void
@@ -506,7 +505,9 @@ 
     {
         status = mbedtls_pk_parse_key(ctx->priv_key,
                                       (const unsigned char *) priv_key_file,
-                                      strlen(priv_key_file) + 1, NULL, 0);
+                                      strlen(priv_key_file) + 1, NULL, 0,
+                                      mbedtls_ctr_drbg_random,
+                                      rand_ctx_get());
 
         if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
         {
@@ -516,17 +517,26 @@ 
                                           (const unsigned char *) priv_key_file,
                                           strlen(priv_key_file) + 1,
                                           (unsigned char *) passbuf,
-                                          strlen(passbuf));
+                                          strlen(passbuf),
+                                          mbedtls_ctr_drbg_random,
+                                          rand_ctx_get());
         }
     }
     else
     {
-        status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
+        status = mbedtls_pk_parse_keyfile(ctx->priv_key,
+                                          priv_key_file,
+                                          NULL,
+                                          mbedtls_ctr_drbg_random,
+                                          rand_ctx_get());
         if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
         {
             char passbuf[512] = {0};
             pem_password_callback(passbuf, 512, 0, NULL);
-            status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
+            status = mbedtls_pk_parse_keyfile(ctx->priv_key,
+                                              priv_key_file, passbuf,
+                                              mbedtls_ctr_drbg_random,
+                                              rand_ctx_get());
         }
     }
     if (!mbed_ok(status))
@@ -542,7 +552,10 @@ 
         return 1;
     }
 
-    if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key)))
+    if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk,
+                                       ctx->priv_key,
+                                       mbedtls_ctr_drbg_random,
+                                       rand_ctx_get())))
     {
         msg(M_WARN, "Private key does not match the certificate");
         return 1;
@@ -558,7 +571,6 @@ 
  * @param ctx_voidptr   Management external key context.
  * @param f_rng         (Unused)
  * @param p_rng         (Unused)
- * @param mode          RSA mode (should be RSA_PRIVATE).
  * @param md_alg        Message digest ('hash') algorithm type.
  * @param hashlen       Length of hash (overridden by length specified by md_alg
  *                      if md_alg != MBEDTLS_MD_NONE).
@@ -572,7 +584,7 @@ 
  */
 static inline int
 external_pkcs1_sign( void *ctx_voidptr,
-                     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode,
+                     int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
                      mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash,
                      unsigned char *sig )
 {
@@ -587,11 +599,6 @@ 
         return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
     }
 
-    if (MBEDTLS_RSA_PRIVATE != mode)
-    {
-        return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
-    }
-
     /*
      * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW,
      * but TLSv1.2 needs the full suite of hashes.
@@ -979,12 +986,16 @@ 
 int
 tls_version_max(void)
 {
-#if defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_3)
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    return TLS_VER_1_3;
+#elif defined(MBEDTLS_SSL_PROTO_TLS1_2)
     return TLS_VER_1_2;
-#elif defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_2)
+#elif defined(MBEDTLS_SSL_PROTO_TLS1_1)
     return TLS_VER_1_1;
-#else
+#elif defined(MBEDTLS_SSL_PROTO_TLS1)
     return TLS_VER_1_0;
+#else /* if defined(MBEDTLS_SSL_PROTO_TLS1_3) */
+    #error "mbedtls is compiled without support for any version of TLS."
 #endif
 }
 
@@ -1006,23 +1017,36 @@ 
 
     switch (tls_ver)
     {
+#if defined(MBEDTLS_SSL_PROTO_TLS1)
         case TLS_VER_1_0:
             *major = MBEDTLS_SSL_MAJOR_VERSION_3;
             *minor = MBEDTLS_SSL_MINOR_VERSION_1;
             break;
+#endif
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_1)
         case TLS_VER_1_1:
             *major = MBEDTLS_SSL_MAJOR_VERSION_3;
             *minor = MBEDTLS_SSL_MINOR_VERSION_2;
             break;
+#endif
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         case TLS_VER_1_2:
             *major = MBEDTLS_SSL_MAJOR_VERSION_3;
             *minor = MBEDTLS_SSL_MINOR_VERSION_3;
             break;
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+        case TLS_VER_1_3:
+            *major = MBEDTLS_SSL_MAJOR_VERSION_3;
+            *minor = MBEDTLS_SSL_MINOR_VERSION_4;
+            break;
+#endif
 
         default:
-            msg(M_FATAL, "%s: invalid TLS version %d", __func__, tls_ver);
+            msg(M_FATAL, "%s: invalid or unsupported TLS version %d", __func__, tls_ver);
             break;
     }
 }
@@ -1153,9 +1177,9 @@ 
             (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT)
             &SSLF_TLS_VERSION_MIN_MASK;
 
-        /* default to TLS 1.0 */
+        /* default to TLS 1.2 */
         int major = MBEDTLS_SSL_MAJOR_VERSION_3;
-        int minor = MBEDTLS_SSL_MINOR_VERSION_1;
+        int minor = MBEDTLS_SSL_MINOR_VERSION_3;
 
         if (tls_version_min > TLS_VER_UNSPEC)
         {
@@ -1171,12 +1195,16 @@ 
             (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT)
             &SSLF_TLS_VERSION_MAX_MASK;
 
+        /* default to TLS 1.3 */
+        int major = MBEDTLS_SSL_MAJOR_VERSION_3;
+        int minor = MBEDTLS_SSL_MINOR_VERSION_4;
+
         if (tls_version_max > TLS_VER_UNSPEC)
         {
-            int major, minor;
             tls_version_to_major_minor(tls_version_max, &major, &minor);
-            mbedtls_ssl_conf_max_version(ks_ssl->ssl_config, major, minor);
         }
+
+        mbedtls_ssl_conf_max_version(ks_ssl->ssl_config, major, minor);
     }
 
 #ifdef HAVE_EXPORT_KEYING_MATERIAL
@@ -1188,7 +1216,7 @@ 
     /* Initialise SSL context */
     ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context);
     mbedtls_ssl_init(ks_ssl->ctx);
-    mbedtls_ssl_setup(ks_ssl->ctx, ks_ssl->ssl_config);
+    mbed_ok(mbedtls_ssl_setup(ks_ssl->ctx, ks_ssl->ssl_config));
 
     /* Initialise BIOs */
     ALLOC_OBJ_CLEAR(ks_ssl->bio_ctx, bio_ctx);
diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c
index a1ddf8d..33c3769 100644
--- a/src/openvpn/ssl_verify_mbedtls.c
+++ b/src/openvpn/ssl_verify_mbedtls.c
@@ -432,6 +432,8 @@ 
     }
 }
 
+/* Dummy function because Netscape certificate types are not supported in OpenVPN with mbedtls.
+ * Returns SUCCESS if usage is NS_CERT_CHECK_NONE, FAILURE otherwise. */
 result_t
 x509_verify_ns_cert_type(mbedtls_x509_crt *cert, const int usage)
 {
@@ -439,18 +441,6 @@ 
     {
         return SUCCESS;
     }
-    if (usage == NS_CERT_CHECK_CLIENT)
-    {
-        return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
-                && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT)) ?
-               SUCCESS : FAILURE;
-    }
-    if (usage == NS_CERT_CHECK_SERVER)
-    {
-        return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
-                && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER)) ?
-               SUCCESS : FAILURE;
-    }
 
     return FAILURE;
 }
@@ -461,7 +451,7 @@ 
 {
     msg(D_HANDSHAKE, "Validating certificate key usage");
 
-    if (!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE))
+    if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_KEY_USAGE))
     {
         msg(D_TLS_ERRORS,
             "ERROR: Certificate does not have key usage extension");
@@ -486,9 +476,7 @@ 
 
     if (fFound != SUCCESS)
     {
-        msg(D_TLS_ERRORS,
-            "ERROR: Certificate has key usage %04x, expected one of:",
-            cert->key_usage);
+        msg(D_TLS_ERRORS, "ERROR: Certificate has invalid key usage, expected one of:");
         for (size_t i = 0; i < expected_len && expected_ku[i]; i++)
         {
             msg(D_TLS_ERRORS, " * %04x", expected_ku[i]);
@@ -503,7 +491,7 @@ 
 {
     result_t fFound = FAILURE;
 
-    if (!(cert->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE))
+    if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE))
     {
         msg(D_HANDSHAKE, "Certificate does not have extended key usage extension");
     }