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>
... | ... |
@@ -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 |
{ |
... | ... |
@@ -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"); |