Browse code

Add --tls-cert-profile option.

This allows the user to specify what certificate crypto algorithms to
support. The supported profiles are 'preferred', 'legacy' (default) and
'suiteb', as discussed in <84590a17-1c48-9df2-c48e-4160750b2e33@fox-it.com>
(https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14214.
html).

This fully implements the feature for mbed TLS builds, because for mbed it
is both more easy to implement and the most relevant because mbed TLS 2+
is by default somewhat restrictive by requiring 2048-bit+ for RSA keys.

For OpenSSL, this implements an approximation based on security levels, as
discussed at the hackathon in Karlsruhe.

This patch uses 'legacy' as the default profile following discussion on
the openvpn-devel mailing list. This way this patch can be applied to
both the release/2.4 and master branches. I'll send a follow-up patch for
the master branch to change the default to 'preferred' later.

Signed-off-by: Steffan Karger <steffan.karger@fox-it.com>
Acked-by: Antonio Quartulli <antonio@openvpn.net>
Message-Id: <20171112163636.17434-1-steffan@karger.me>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15848.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Steffan Karger authored on 2017/11/13 01:36:36
Showing 10 changed files
... ...
@@ -321,6 +321,18 @@ Maintainer-visible changes
321 321
   i386/i686 builds on RHEL5.
322 322
 
323 323
 
324
+Version 2.4.5
325
+=============
326
+
327
+New features
328
+------------
329
+- The new option ``--tls-cert-profile`` can be used to restrict the set of
330
+  allowed crypto algorithms in TLS certificates in mbed TLS builds.  The
331
+  default profile is 'legacy' for now, which allows SHA1+, RSA-1024+ and any
332
+  elliptic curve certificates.  The default will be changed to the 'preferred'
333
+  profile in the future, which requires SHA2+, RSA-2048+ and any curve.
334
+
335
+
324 336
 Version 2.4.3
325 337
 =============
326 338
 
... ...
@@ -4917,6 +4917,37 @@ when using mbed TLS or
4917 4917
 OpenSSL.
4918 4918
 .\"*********************************************************
4919 4919
 .TP
4920
+.B \-\-tls\-cert\-profile profile
4921
+Set the allowed cryptographic algorithms for certificates according to
4922
+.B profile\fN.
4923
+
4924
+The following profiles are supported:
4925
+
4926
+.B legacy
4927
+(default): SHA1 and newer, RSA 2048-bit+, any elliptic curve.
4928
+
4929
+.B preferred
4930
+: SHA2 and newer, RSA 2048-bit+, any elliptic curve.
4931
+
4932
+.B suiteb
4933
+: SHA256/SHA384, ECDSA with P-256 or P-384.
4934
+
4935
+This option is only fully supported for mbed TLS builds.  OpenSSL builds use
4936
+the following approximation:
4937
+
4938
+.B legacy
4939
+(default): sets "security level 1"
4940
+
4941
+.B preferred
4942
+: sets "security level 2"
4943
+
4944
+.B suiteb
4945
+: sets "security level 3" and \-\-tls\-cipher "SUITEB128".
4946
+
4947
+OpenVPN will migrate to 'preferred' as default in the future.  Please ensure
4948
+that your keys already comply.
4949
+.\"*********************************************************
4950
+.TP
4920 4951
 .B \-\-tls\-timeout n
4921 4952
 Packet retransmit timeout on TLS control channel
4922 4953
 if no acknowledgment from remote within
... ...
@@ -1016,7 +1016,8 @@ print_openssl_info(const struct options *options)
1016 1016
         }
1017 1017
         if (options->show_tls_ciphers)
1018 1018
         {
1019
-            show_available_tls_ciphers(options->cipher_list);
1019
+            show_available_tls_ciphers(options->cipher_list,
1020
+                                       options->tls_cert_profile);
1020 1021
         }
1021 1022
         if (options->show_curves)
1022 1023
         {
... ...
@@ -599,6 +599,8 @@ static const char usage_message[] =
599 599
 #endif
600 600
     "--tls-cipher l  : A list l of allowable TLS ciphers separated by : (optional).\n"
601 601
     "                : Use --show-tls to see a list of supported TLS ciphers.\n"
602
+    "--tls-cert-profile p : Set the allowed certificate crypto algorithm profile\n"
603
+    "                  (default=legacy).\n"
602 604
     "--tls-timeout n : Packet retransmit timeout on TLS control channel\n"
603 605
     "                  if no ACK from remote within n seconds (default=%d).\n"
604 606
     "--reneg-bytes n : Renegotiate data chan. key after n bytes sent and recvd.\n"
... ...
@@ -875,6 +877,7 @@ init_options(struct options *o, const bool init_gc)
875 875
     o->renegotiate_seconds_min = -1;
876 876
     o->handshake_window = 60;
877 877
     o->transition_window = 3600;
878
+    o->tls_cert_profile = NULL;
878 879
     o->ecdh_curve = NULL;
879 880
 #ifdef ENABLE_X509ALTUSERNAME
880 881
     o->x509_username_field = X509_USERNAME_FIELD_DEFAULT;
... ...
@@ -1753,6 +1756,7 @@ show_settings(const struct options *o)
1753 1753
     SHOW_STR(cryptoapi_cert);
1754 1754
 #endif
1755 1755
     SHOW_STR(cipher_list);
1756
+    SHOW_STR(tls_cert_profile);
1756 1757
     SHOW_STR(tls_verify);
1757 1758
     SHOW_STR(tls_export_cert);
1758 1759
     SHOW_INT(verify_x509_type);
... ...
@@ -2732,6 +2736,7 @@ options_postprocess_verify_ce(const struct options *options, const struct connec
2732 2732
         MUST_BE_UNDEF(pkcs12_file);
2733 2733
 #endif
2734 2734
         MUST_BE_UNDEF(cipher_list);
2735
+        MUST_BE_UNDEF(tls_cert_profile);
2735 2736
         MUST_BE_UNDEF(tls_verify);
2736 2737
         MUST_BE_UNDEF(tls_export_cert);
2737 2738
         MUST_BE_UNDEF(verify_x509_name);
... ...
@@ -7834,6 +7839,11 @@ add_option(struct options *options,
7834 7834
         VERIFY_PERMISSION(OPT_P_GENERAL);
7835 7835
         options->cipher_list = p[1];
7836 7836
     }
7837
+    else if (streq(p[0], "tls-cert-profile") && p[1] && !p[2])
7838
+    {
7839
+        VERIFY_PERMISSION(OPT_P_GENERAL);
7840
+        options->tls_cert_profile = p[1];
7841
+    }
7837 7842
     else if (streq(p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir"))
7838 7843
                                                    || (p[2] && streq(p[1], INLINE_FILE_TAG) ) || !p[2]) && !p[3])
7839 7844
     {
... ...
@@ -502,6 +502,7 @@ struct options
502 502
     const char *priv_key_file;
503 503
     const char *pkcs12_file;
504 504
     const char *cipher_list;
505
+    const char *tls_cert_profile;
505 506
     const char *ecdh_curve;
506 507
     const char *tls_verify;
507 508
     int verify_x509_type;
... ...
@@ -616,6 +616,9 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx)
616 616
         tls_ctx_client_new(new_ctx);
617 617
     }
618 618
 
619
+    /* Restrict allowed certificate crypto algorithms */
620
+    tls_ctx_set_cert_profile(new_ctx, options->tls_cert_profile);
621
+
619 622
     /* Allowable ciphers */
620 623
     /* Since @SECLEVEL also influces loading of certificates, set the
621 624
      * cipher restrictions before loading certificates */
... ...
@@ -177,6 +177,16 @@ void tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags);
177 177
 void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers);
178 178
 
179 179
 /**
180
+ * Set the TLS certificate profile.  The profile defines which crypto
181
+ * algorithms may be used in the supplied certificate.
182
+ *
183
+ * @param ctx           TLS context to restrict, must be valid.
184
+ * @param profile       The profile name ('preferred', 'legacy' or 'suiteb').
185
+ *                      Defaults to 'preferred' if NULL.
186
+ */
187
+void tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile);
188
+
189
+/**
180 190
  * Check our certificate notBefore and notAfter fields, and warn if the cert is
181 191
  * either not yet valid or has expired.  Note that this is a non-fatal error,
182 192
  * since we compare against the system time, which might be incorrect.
... ...
@@ -505,9 +515,12 @@ void print_details(struct key_state_ssl *ks_ssl, const char *prefix);
505 505
  * Show the TLS ciphers that are available for us to use in the OpenSSL
506 506
  * library.
507 507
  *
508
- * @param               - list of allowed TLS cipher, or NULL.
508
+ * @param cipher_list       list of allowed TLS cipher, or NULL.
509
+ * @param tls_cert_profile  TLS certificate crypto profile name.
509 510
  */
510
-void show_available_tls_ciphers(const char *tls_ciphers);
511
+void
512
+show_available_tls_ciphers(const char *cipher_list,
513
+                           const char *tls_cert_profile);
511 514
 
512 515
 /*
513 516
  * Show the available elliptic curves in the crypto library
... ...
@@ -62,6 +62,34 @@
62 62
 #include <mbedtls/pem.h>
63 63
 #include <mbedtls/sha256.h>
64 64
 
65
+static const mbedtls_x509_crt_profile openvpn_x509_crt_profile_legacy =
66
+{
67
+    /* Hashes from SHA-1 and above */
68
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
69
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) |
70
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
71
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
72
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
73
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
74
+    0xFFFFFFF, /* Any PK alg    */
75
+    0xFFFFFFF, /* Any curve     */
76
+    1024,      /* RSA-1024 and larger */
77
+};
78
+
79
+static const mbedtls_x509_crt_profile openvpn_x509_crt_profile_preferred =
80
+{
81
+    /* SHA-2 and above */
82
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
83
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
84
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
85
+    MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
86
+    0xFFFFFFF, /* Any PK alg    */
87
+    0xFFFFFFF, /* Any curve     */
88
+    2048,      /* RSA-2048 and larger */
89
+};
90
+
91
+#define openvpn_x509_crt_profile_suiteb mbedtls_x509_crt_profile_suiteb;
92
+
65 93
 void
66 94
 tls_init_lib(void)
67 95
 {
... ...
@@ -251,6 +279,27 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
251 251
 }
252 252
 
253 253
 void
254
+tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile)
255
+{
256
+    if (!profile || 0 == strcmp(profile, "legacy"))
257
+    {
258
+        ctx->cert_profile = openvpn_x509_crt_profile_legacy;
259
+    }
260
+    else if (0 == strcmp(profile, "preferred"))
261
+    {
262
+        ctx->cert_profile = openvpn_x509_crt_profile_preferred;
263
+    }
264
+    else if (0 == strcmp(profile, "suiteb"))
265
+    {
266
+        ctx->cert_profile = openvpn_x509_crt_profile_suiteb;
267
+    }
268
+    else
269
+    {
270
+        msg (M_FATAL, "ERROR: Invalid cert profile: %s", profile);
271
+    }
272
+}
273
+
274
+void
254 275
 tls_ctx_check_cert_time(const struct tls_root_ctx *ctx)
255 276
 {
256 277
     ASSERT(ctx);
... ...
@@ -917,6 +966,8 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl,
917 917
     mbedtls_ssl_conf_rng(&ks_ssl->ssl_config, mbedtls_ctr_drbg_random,
918 918
                          rand_ctx_get());
919 919
 
920
+    mbedtls_ssl_conf_cert_profile(&ks_ssl->ssl_config, &ssl_ctx->cert_profile);
921
+
920 922
     if (ssl_ctx->allowed_ciphers)
921 923
     {
922 924
         mbedtls_ssl_conf_ciphersuites(&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers);
... ...
@@ -1271,12 +1322,14 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
1271 1271
 }
1272 1272
 
1273 1273
 void
1274
-show_available_tls_ciphers(const char *cipher_list)
1274
+show_available_tls_ciphers(const char *cipher_list,
1275
+                           const char *tls_cert_profile)
1275 1276
 {
1276 1277
     struct tls_root_ctx tls_ctx;
1277 1278
     const int *ciphers = mbedtls_ssl_list_ciphersuites();
1278 1279
 
1279 1280
     tls_ctx_server_new(&tls_ctx);
1281
+    tls_ctx_set_cert_profile(&tls_ctx, tls_cert_profile);
1280 1282
     tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
1281 1283
 
1282 1284
     if (tls_ctx.allowed_ciphers)
... ...
@@ -82,6 +82,7 @@ struct tls_root_ctx {
82 82
     struct external_context *external_key; /**< Management external key */
83 83
 #endif
84 84
     int *allowed_ciphers;       /**< List of allowed ciphers for this connection */
85
+    mbedtls_x509_crt_profile cert_profile; /**< Allowed certificate types */
85 86
 };
86 87
 
87 88
 struct key_state_ssl {
... ...
@@ -384,6 +384,40 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
384 384
 }
385 385
 
386 386
 void
387
+tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile)
388
+{
389
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000)
390
+    /* OpenSSL does not have certificate profiles, but a complex set of
391
+     * callbacks that we could try to implement to achieve something similar.
392
+     * For now, use OpenSSL's security levels to achieve similar (but not equal)
393
+     * behaviour. */
394
+    if (!profile || 0 == strcmp(profile, "legacy"))
395
+    {
396
+        SSL_CTX_set_security_level(ctx->ctx, 1);
397
+    }
398
+    else if (0 == strcmp(profile, "preferred"))
399
+    {
400
+        SSL_CTX_set_security_level(ctx->ctx, 2);
401
+    }
402
+    else if (0 == strcmp(profile, "suiteb"))
403
+    {
404
+        SSL_CTX_set_security_level(ctx->ctx, 3);
405
+        SSL_CTX_set_cipher_list(ctx->ctx, "SUITEB128");
406
+    }
407
+    else
408
+    {
409
+        msg(M_FATAL, "ERROR: Invalid cert profile: %s", profile);
410
+    }
411
+#else
412
+    if (profile)
413
+    {
414
+        msg(M_WARN, "WARNING: OpenSSL 1.0.1 does not support --tls-cert-profile"
415
+            ", ignoring user-set profile: '%s'", profile);
416
+    }
417
+#endif
418
+}
419
+
420
+void
387 421
 tls_ctx_check_cert_time(const struct tls_root_ctx *ctx)
388 422
 {
389 423
     int ret;
... ...
@@ -1722,7 +1756,8 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix)
1722 1722
 }
1723 1723
 
1724 1724
 void
1725
-show_available_tls_ciphers(const char *cipher_list)
1725
+show_available_tls_ciphers(const char *cipher_list,
1726
+                           const char *tls_cert_profile)
1726 1727
 {
1727 1728
     struct tls_root_ctx tls_ctx;
1728 1729
     SSL *ssl;
... ...
@@ -1742,6 +1777,7 @@ show_available_tls_ciphers(const char *cipher_list)
1742 1742
         crypto_msg(M_FATAL, "Cannot create SSL object");
1743 1743
     }
1744 1744
 
1745
+    tls_ctx_set_cert_profile(&tls_ctx, tls_cert_profile);
1745 1746
     tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
1746 1747
 
1747 1748
     printf("Available TLS Ciphers,\n");