diff options
author | Bernhard Schmidt <berni@debian.org> | 2020-09-01 16:52:17 +0200 |
---|---|---|
committer | Bernhard Schmidt <berni@debian.org> | 2020-09-01 16:52:17 +0200 |
commit | 9fc3b98112217f2d92a67977dbde0987cc7a1803 (patch) | |
tree | 29fcc8654ee65d9dd89ade797bea2f3d9dfd9cfd /src/openvpn/ssl_openssl.c | |
parent | a8758c0e03eed188dcb9da0e4fd781a67c25bf1e (diff) | |
parent | 69b02b1f7fd609d84ace13ab04697158de2418a9 (diff) |
Merge branch 'debian/experimental-2.5'
Diffstat (limited to 'src/openvpn/ssl_openssl.c')
-rw-r--r-- | src/openvpn/ssl_openssl.c | 707 |
1 files changed, 474 insertions, 233 deletions
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 19509b7..5ba7440 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -34,7 +34,7 @@ #include "syshead.h" -#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) +#if defined(ENABLE_CRYPTO_OPENSSL) #include "errlevel.h" #include "buffer.h" @@ -52,10 +52,15 @@ #include "ssl_verify_openssl.h" +#include <openssl/bn.h> +#include <openssl/crypto.h> +#include <openssl/dh.h> +#include <openssl/dsa.h> #include <openssl/err.h> #include <openssl/pkcs12.h> +#include <openssl/rsa.h> #include <openssl/x509.h> -#include <openssl/crypto.h> +#include <openssl/ssl.h> #ifndef OPENSSL_NO_EC #include <openssl/ec.h> #endif @@ -110,6 +115,11 @@ tls_ctx_server_new(struct tls_root_ctx *ctx) { crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_server_method"); } + if (ERR_peek_error() != 0) + { + crypto_msg(M_WARN, "Warning: TLS server context initialisation " + "has warnings."); + } } void @@ -123,6 +133,11 @@ tls_ctx_client_new(struct tls_root_ctx *ctx) { crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_client_method"); } + if (ERR_peek_error() != 0) + { + crypto_msg(M_WARN, "Warning: TLS client context initialisation " + "has warnings."); + } } void @@ -149,13 +164,14 @@ key_state_export_keying_material(struct key_state_ssl *ssl, { if (session->opt->ekm_size > 0) { -#if (OPENSSL_VERSION_NUMBER >= 0x10001000) unsigned int size = session->opt->ekm_size; struct gc_arena gc = gc_new(); unsigned char *ekm = (unsigned char *) gc_malloc(size, true, &gc); if (SSL_export_keying_material(ssl->ssl, ekm, size, - session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0)) + session->opt->ekm_label, + session->opt->ekm_label_size, + NULL, 0, 0)) { unsigned int len = (size * 2) + 2; @@ -171,7 +187,6 @@ key_state_export_keying_material(struct key_state_ssl *ssl, setenv_del(session->opt->es, "exported_keying_material"); } gc_free(&gc); -#endif /* if (OPENSSL_VERSION_NUMBER >= 0x10001000) */ } } @@ -209,13 +224,34 @@ info_callback(INFO_CALLBACK_SSL_CONST SSL *s, int where, int ret) int tls_version_max(void) { -#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) +#if defined(TLS1_3_VERSION) + /* If this is defined we can safely assume TLS 1.3 support */ return TLS_VER_1_3; +#elif OPENSSL_VERSION_NUMBER >= 0x10100000L + /* + * If TLS_VER_1_3 is not defined, we were compiled against a version that + * did not support TLS 1.3. + * + * However, the library we are *linked* against might be OpenSSL 1.1.1 + * and therefore supports TLS 1.3. This needs to be checked at runtime + * since we can be compiled against 1.1.0 and then the library can be + * upgraded to 1.1.1. + * We only need to check this for OpenSSL versions that can be + * upgraded to 1.1.1 without recompile (>= 1.1.0) + */ + if (OpenSSL_version_num() >= 0x1010100fL) + { + return TLS_VER_1_3; + } + else + { + return TLS_VER_1_2; + } #elif defined(TLS1_2_VERSION) || defined(SSL_OP_NO_TLSv1_2) return TLS_VER_1_2; #elif defined(TLS1_1_VERSION) || defined(SSL_OP_NO_TLSv1_1) return TLS_VER_1_1; -#else +#else /* if defined(TLS1_3_VERSION) */ return TLS_VER_1_0; #endif } @@ -236,12 +272,25 @@ openssl_tls_version(int ver) { return TLS1_2_VERSION; } -#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) else if (ver == TLS_VER_1_3) { + /* + * Supporting the library upgraded to TLS1.3 without recompile + * is enough to support here with a simple constant that the same + * as in the TLS 1.3, so spec it is very unlikely that OpenSSL + * will change this constant + */ +#ifndef TLS1_3_VERSION + /* + * We do not want to define TLS_VER_1_3 if not defined + * since other parts of the code use the existance of this macro + * as proxy for TLS 1.3 support + */ + return 0x0304; +#else return TLS1_3_VERSION; - } #endif + } return 0; } @@ -280,18 +329,12 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) { ASSERT(NULL != ctx); - /* default certificate verification flags */ - int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; - /* process SSL options */ long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET; #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE sslopt |= SSL_OP_CIPHER_SERVER_PREFERENCE; #endif -#ifdef SSL_OP_NO_COMPRESSION - /* Disable compression - flag not available in OpenSSL 0.9.8 */ sslopt |= SSL_OP_NO_COMPRESSION; -#endif SSL_CTX_set_options(ctx->ctx, sslopt); @@ -307,17 +350,16 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) SSL_CTX_set_default_passwd_cb(ctx->ctx, pem_password_callback); /* Require peer certificate verification */ -#if P2MP_SERVER + int verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) { - flags = 0; + verify_flags = 0; } else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) { - flags = SSL_VERIFY_PEER; + verify_flags = SSL_VERIFY_PEER; } -#endif - SSL_CTX_set_verify(ctx->ctx, flags, verify_callback); + SSL_CTX_set_verify(ctx->ctx, verify_flags, verify_callback); SSL_CTX_set_info_callback(ctx->ctx, info_callback); @@ -325,28 +367,8 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) } void -tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) +convert_tls_list_to_openssl(char *openssl_ciphers, size_t len,const char *ciphers) { - if (ciphers == NULL) - { - /* Use sane default TLS cipher list */ - if (!SSL_CTX_set_cipher_list(ctx->ctx, - /* Use openssl's default list as a basis */ - "DEFAULT" - /* Disable export ciphers and openssl's 'low' and 'medium' ciphers */ - ":!EXP:!LOW:!MEDIUM" - /* Disable static (EC)DH keys (no forward secrecy) */ - ":!kDH:!kECDH" - /* Disable DSA private keys */ - ":!DSS" - /* Disable unsupported TLS modes */ - ":!PSK:!SRP:!kRSA")) - { - crypto_msg(M_FATAL, "Failed to set default TLS cipher list."); - } - return; - } - /* Parse supplied cipher list and pass on to OpenSSL */ size_t begin_of_cipher, end_of_cipher; @@ -355,12 +377,9 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) const tls_cipher_name_pair *cipher_pair; - char openssl_ciphers[4096]; size_t openssl_ciphers_len = 0; openssl_ciphers[0] = '\0'; - ASSERT(NULL != ctx); - /* Translate IANA cipher suite names to OpenSSL names */ begin_of_cipher = end_of_cipher = 0; for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher) @@ -397,11 +416,11 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) /* Make sure new cipher name fits in cipher string */ if ((SIZE_MAX - openssl_ciphers_len) < current_cipher_len - || ((sizeof(openssl_ciphers)-1) < openssl_ciphers_len + current_cipher_len)) + || (len - 1) < (openssl_ciphers_len + current_cipher_len)) { msg(M_FATAL, "Failed to set restricted TLS cipher list, too long (>%d).", - (int)sizeof(openssl_ciphers)-1); + (int)(len - 1)); } /* Concatenate cipher name to OpenSSL cipher string */ @@ -417,6 +436,35 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) { openssl_ciphers[openssl_ciphers_len-1] = '\0'; } +} + +void +tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) +{ + if (ciphers == NULL) + { + /* Use sane default TLS cipher list */ + if (!SSL_CTX_set_cipher_list(ctx->ctx, + /* Use openssl's default list as a basis */ + "DEFAULT" + /* Disable export ciphers and openssl's 'low' and 'medium' ciphers */ + ":!EXP:!LOW:!MEDIUM" + /* Disable static (EC)DH keys (no forward secrecy) */ + ":!kDH:!kECDH" + /* Disable DSA private keys */ + ":!DSS" + /* Disable unsupported TLS modes */ + ":!PSK:!SRP:!kRSA")) + { + crypto_msg(M_FATAL, "Failed to set default TLS cipher list."); + } + return; + } + + char openssl_ciphers[4096]; + convert_tls_list_to_openssl(openssl_ciphers, sizeof(openssl_ciphers), ciphers); + + ASSERT(NULL != ctx); /* Set OpenSSL cipher list */ if (!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers)) @@ -462,10 +510,10 @@ tls_ctx_restrict_ciphers_tls13(struct tls_root_ctx *ctx, const char *ciphers) return; } -#if (OPENSSL_VERSION_NUMBER < 0x1010100fL) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3) - crypto_msg(M_WARN, "Not compiled with OpenSSL 1.1.1 or higher, or without TLS 1.3 support. " - "Ignoring TLS 1.3 only tls-ciphersuites '%s' setting.", - ciphers); +#if !defined(TLS1_3_VERSION) + crypto_msg(M_WARN, "Not compiled with OpenSSL 1.1.1 or higher. " + "Ignoring TLS 1.3 only tls-ciphersuites '%s' setting.", + ciphers); #else ASSERT(NULL != ctx); @@ -506,13 +554,64 @@ tls_ctx_set_cert_profile(struct tls_root_ctx *ctx, const char *profile) { msg(M_FATAL, "ERROR: Invalid cert profile: %s", profile); } -#else +#else /* ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL */ if (profile) { - msg(M_WARN, "WARNING: OpenSSL 1.0.1 does not support --tls-cert-profile" + msg(M_WARN, "WARNING: OpenSSL 1.0.2 does not support --tls-cert-profile" ", ignoring user-set profile: '%s'", profile); } -#endif +#endif /* ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL */ +} + +void +tls_ctx_set_tls_groups(struct tls_root_ctx *ctx, const char *groups) +{ + ASSERT(ctx); + struct gc_arena gc = gc_new(); + /* This method could be as easy as + * SSL_CTX_set1_groups_list(ctx->ctx, groups) + * but OpenSSL does not like the name secp256r1 for prime256v1 + * This is one of the important curves. + * To support the same name for OpenSSL and mbedTLS, we do + * this dance. + */ + + int groups_count = get_num_elements(groups, ':'); + + int *glist; + /* Allocate an array for them */ + ALLOC_ARRAY_CLEAR_GC(glist, int, groups_count, &gc); + + /* Parse allowed ciphers, getting IDs */ + int glistlen = 0; + char *tmp_groups = string_alloc(groups, &gc); + + const char *token; + while ((token = strsep(&tmp_groups, ":"))) + { + if (streq(token, "secp256r1")) + { + token = "prime256v1"; + } + int nid = OBJ_sn2nid(token); + + if (nid == 0) + { + msg(M_WARN, "Warning unknown curve/group specified: %s", token); + } + else + { + glist[glistlen] = nid; + glistlen++; + } + } + + if (!SSL_CTX_set1_groups(ctx->ctx, glist, glistlen)) + { + crypto_msg(M_FATAL, "Failed to set allowed TLS group list: %s", + groups); + } + gc_free(&gc); } void @@ -523,18 +622,11 @@ tls_ctx_check_cert_time(const struct tls_root_ctx *ctx) ASSERT(ctx); -#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) - /* OpenSSL 1.0.2 and up */ cert = SSL_CTX_get0_certificate(ctx->ctx); -#else - /* OpenSSL 1.0.1 and earlier need an SSL object to get at the certificate */ - SSL *ssl = SSL_new(ctx->ctx); - cert = SSL_get_certificate(ssl); -#endif if (cert == NULL) { - goto cleanup; /* Nothing to check if there is no certificate */ + return; /* Nothing to check if there is no certificate */ } ret = X509_cmp_time(X509_get0_notBefore(cert), NULL); @@ -556,27 +648,20 @@ tls_ctx_check_cert_time(const struct tls_root_ctx *ctx) { msg(M_WARN, "WARNING: Your certificate has expired!"); } - -cleanup: -#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER) - SSL_free(ssl); -#endif - return; } void tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file, - const char *dh_file_inline - ) + bool dh_file_inline) { DH *dh; BIO *bio; ASSERT(NULL != ctx); - if (!strcmp(dh_file, INLINE_FILE_TAG) && dh_file_inline) + if (dh_file_inline) { - if (!(bio = BIO_new_mem_buf((char *)dh_file_inline, -1))) + if (!(bio = BIO_new_mem_buf((char *)dh_file, -1))) { crypto_msg(M_FATAL, "Cannot open memory BIO for inline DH parameters"); } @@ -595,7 +680,8 @@ tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file, if (!dh) { - crypto_msg(M_FATAL, "Cannot load DH parameters from %s", dh_file); + crypto_msg(M_FATAL, "Cannot load DH parameters from %s", + print_key_filename(dh_file, dh_file_inline)); } if (!SSL_CTX_set_tmp_dh(ctx->ctx, dh)) { @@ -628,7 +714,6 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name } else { -#if OPENSSL_VERSION_NUMBER >= 0x10002000L #if (OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) /* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter @@ -639,29 +724,6 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name * so do nothing */ #endif return; -#else - /* For older OpenSSL we have to extract the curve from key on our own */ - EC_KEY *eckey = NULL; - const EC_GROUP *ecgrp = NULL; - EVP_PKEY *pkey = NULL; - - /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */ - SSL *ssl = SSL_new(ctx->ctx); - if (!ssl) - { - crypto_msg(M_FATAL, "SSL_new failed"); - } - pkey = SSL_get_privatekey(ssl); - SSL_free(ssl); - - msg(D_TLS_DEBUG, "Extracting ECDH curve from private key"); - - if (pkey != NULL && (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL - && (ecgrp = EC_KEY_get0_group(eckey)) != NULL) - { - nid = EC_GROUP_get_curve_name(ecgrp); - } -#endif } /* Translate NID back to name , just for kicks */ @@ -699,9 +761,7 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, - const char *pkcs12_file_inline, - bool load_ca_file - ) + bool pkcs12_file_inline, bool load_ca_file) { FILE *fp; EVP_PKEY *pkey; @@ -713,11 +773,11 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, ASSERT(NULL != ctx); - if (!strcmp(pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline) + if (pkcs12_file_inline) { BIO *b64 = BIO_new(BIO_f_base64()); - BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline, - (int) strlen(pkcs12_file_inline)); + BIO *bio = BIO_new_mem_buf((void *) pkcs12_file, + (int) strlen(pkcs12_file)); ASSERT(b64 && bio); BIO_push(b64, bio); p12 = d2i_PKCS12_bio(b64, NULL); @@ -873,28 +933,19 @@ tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio, bool optional) } } -/* Like tls_ctx_load_cert, but returns a copy of the certificate in **X509 */ -static void -tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline, X509 **x509 - ) +void +tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file, + bool cert_file_inline) { BIO *in = NULL; X509 *x = NULL; int ret = 0; - bool inline_file = false; ASSERT(NULL != ctx); - if (NULL != x509) - { - ASSERT(NULL == *x509); - } - - inline_file = (strcmp(cert_file, INLINE_FILE_TAG) == 0); - if (inline_file && cert_file_inline) + if (cert_file_inline) { - in = BIO_new_mem_buf((char *)cert_file_inline, -1); + in = BIO_new_mem_buf((char *) cert_file, -1); } else { @@ -925,7 +976,7 @@ tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx, end: if (!ret) { - if (inline_file) + if (cert_file_inline) { crypto_msg(M_FATAL, "Cannot load inline certificate file"); } @@ -943,27 +994,15 @@ end: { BIO_free(in); } - if (x509) - { - *x509 = x; - } - else if (x) + if (x) { X509_free(x); } } -void -tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline) -{ - tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, NULL); -} - int tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, - const char *priv_key_file_inline - ) + bool priv_key_file_inline) { SSL_CTX *ssl_ctx = NULL; BIO *in = NULL; @@ -974,9 +1013,9 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, ssl_ctx = ctx->ctx; - if (!strcmp(priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline) + if (priv_key_file_inline) { - in = BIO_new_mem_buf((char *)priv_key_file_inline, -1); + in = BIO_new_mem_buf((char *) priv_key_file, -1); } else { @@ -991,6 +1030,11 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, pkey = PEM_read_bio_PrivateKey(in, NULL, SSL_CTX_get_default_passwd_cb(ctx->ctx), SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx)); + if (!pkey) + { + pkey = engine_load_key(priv_key_file, ctx->ctx); + } + if (!pkey || !SSL_CTX_use_PrivateKey(ssl_ctx, pkey)) { #ifdef ENABLE_MANAGEMENT @@ -999,7 +1043,8 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL); } #endif - crypto_msg(M_WARN, "Cannot load private key file %s", priv_key_file); + crypto_msg(M_WARN, "Cannot load private key file %s", + print_key_filename(priv_key_file, priv_key_file_inline)); goto end; } @@ -1024,7 +1069,7 @@ end: void backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, - const char *crl_inline) + bool crl_inline) { BIO *in = NULL; @@ -1051,9 +1096,9 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); - if (!strcmp(crl_file, INLINE_FILE_TAG) && crl_inline) + if (crl_inline) { - in = BIO_new_mem_buf((char *)crl_inline, -1); + in = BIO_new_mem_buf((char *) crl_file, -1); } else { @@ -1062,7 +1107,8 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, if (in == NULL) { - msg(M_WARN, "CRL: cannot read: %s", crl_file); + msg(M_WARN, "CRL: cannot read: %s", + print_key_filename(crl_file, crl_inline)); goto end; } @@ -1084,14 +1130,16 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, break; } - crypto_msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file); + crypto_msg(M_WARN, "CRL: cannot read CRL from file %s", + print_key_filename(crl_file, crl_inline)); break; } if (!X509_STORE_add_crl(store, crl)) { X509_CRL_free(crl); - crypto_msg(M_WARN, "CRL: cannot add %s to store", crl_file); + crypto_msg(M_WARN, "CRL: cannot add %s to store", + print_key_filename(crl_file, crl_inline)); break; } X509_CRL_free(crl); @@ -1103,7 +1151,7 @@ end: } -#ifdef MANAGMENT_EXTERNAL_KEY +#ifdef ENABLE_MANAGEMENT /* encrypt */ static int @@ -1133,7 +1181,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i static int openvpn_extkey_rsa_finish(RSA *rsa) { - /* meth was allocated in tls_ctx_use_external_private_key() ; since + /* meth was allocated in tls_ctx_use_management_external_key() ; since * this function is called when the parent RSA object is destroyed, * it is no longer used after this point so kill it. */ const RSA_METHOD *meth = RSA_get_method(rsa); @@ -1141,74 +1189,93 @@ openvpn_extkey_rsa_finish(RSA *rsa) return 1; } -/* sign arbitrary data */ +/* + * Convert OpenSSL's constant to the strings used in the management + * interface query + */ +const char * +get_rsa_padding_name(const int padding) +{ + switch (padding) + { + case RSA_PKCS1_PADDING: + return "RSA_PKCS1_PADDING"; + + case RSA_NO_PADDING: + return "RSA_NO_PADDING"; + + default: + return "UNKNOWN"; + } +} + +/** + * Pass the input hash in 'dgst' to management and get the signature back. + * + * @param dgst hash to be signed + * @param dgstlen len of data in dgst + * @param sig On successful return signature is in sig. + * @param siglen length of buffer sig + * @param algorithm padding/hashing algorithm for the signature + * + * @return signature length or -1 on error. + */ static int -rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +get_sig_from_man(const unsigned char *dgst, unsigned int dgstlen, + unsigned char *sig, unsigned int siglen, + const char *algorithm) { - /* optional app data in rsa->meth->app_data; */ char *in_b64 = NULL; char *out_b64 = NULL; - int ret = -1; - int len; + int len = -1; - if (padding != RSA_PKCS1_PADDING) - { - RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); - goto done; - } + int bencret = openvpn_base64_encode(dgst, dgstlen, &in_b64); - /* convert 'from' to base64 */ - if (openvpn_base64_encode(from, flen, &in_b64) <= 0) + if (management && bencret > 0) { - goto done; - } + out_b64 = management_query_pk_sig(management, in_b64, algorithm); - /* call MI for signature */ - if (management) - { - out_b64 = management_query_rsa_sig(management, in_b64); } - if (!out_b64) + if (out_b64) { - goto done; + len = openvpn_base64_decode(out_b64, sig, siglen); } - /* decode base64 signature to binary */ - len = RSA_size(rsa); - ret = openvpn_base64_decode(out_b64, to, len); + free(in_b64); + free(out_b64); + return len; +} - /* verify length */ - if (ret != len) - { - ret = -1; - } +/* sign arbitrary data */ +static int +rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, + int padding) +{ + unsigned int len = RSA_size(rsa); + int ret = -1; -done: - if (in_b64) + if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING) { - free(in_b64); - } - if (out_b64) - { - free(out_b64); + RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + return -1; } - return ret; + + ret = get_sig_from_man(from, flen, to, len, get_rsa_padding_name(padding)); + + return (ret == len) ? ret : -1; } -int -tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline) +static int +tls_ctx_use_external_rsa_key(struct tls_root_ctx *ctx, EVP_PKEY *pkey) { RSA *rsa = NULL; RSA *pub_rsa; RSA_METHOD *rsa_meth; - X509 *cert = NULL; ASSERT(NULL != ctx); - tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, &cert); - - ASSERT(NULL != cert); + pub_rsa = EVP_PKEY_get0_RSA(pkey); + ASSERT(NULL != pub_rsa); /* allocate custom RSA method object */ rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method", @@ -1230,18 +1297,6 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, goto err; } - /* get the public key */ - EVP_PKEY *pkey = X509_get0_pubkey(cert); - ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */ - pub_rsa = EVP_PKEY_get0_RSA(pkey); - - /* Certificate might not be RSA but DSA or EC */ - if (!pub_rsa) - { - crypto_msg(M_WARN, "management-external-key requires a RSA certificate"); - goto err; - } - /* initialize RSA object */ const BIGNUM *n = NULL; const BIGNUM *e = NULL; @@ -1250,8 +1305,10 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY); if (!RSA_set_method(rsa, rsa_meth)) { + RSA_meth_free(rsa_meth); goto err; } + /* from this point rsa_meth will get freed with rsa */ /* bind our custom RSA object to ssl_ctx */ if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) @@ -1259,15 +1316,10 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, goto err; } - X509_free(cert); RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ - return 0; + return 1; err: - if (cert) - { - X509_free(cert); - } if (rsa) { RSA_free(rsa); @@ -1279,11 +1331,195 @@ err: RSA_meth_free(rsa_meth); } } - crypto_msg(M_FATAL, "Cannot enable SSL external private key capability"); + return 0; +} + +#if ((OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) \ + || LIBRESSL_VERSION_NUMBER > 0x2090000fL) \ + && !defined(OPENSSL_NO_EC) + +/* called when EC_KEY is destroyed */ +static void +openvpn_extkey_ec_finish(EC_KEY *ec) +{ + /* release the method structure */ + const EC_KEY_METHOD *ec_meth = EC_KEY_get_method(ec); + EC_KEY_METHOD_free((EC_KEY_METHOD *) ec_meth); +} + +/* EC_KEY_METHOD callback: sign(). + * Sign the hash using EC key and return DER encoded signature in sig, + * its length in siglen. Return value is 1 on success, 0 on error. + */ +static int +ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig, + unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec) +{ + int capacity = ECDSA_size(ec); + /* + * ECDSA does not seem to have proper constants for paddings since + * there are only signatures without padding at the moment, use + * a generic ECDSA for the moment + */ + int len = get_sig_from_man(dgst, dgstlen, sig, capacity, "ECDSA"); + + if (len > 0) + { + *siglen = len; + return 1; + } + return 0; +} + +/* EC_KEY_METHOD callback: sign_setup(). We do no precomputations */ +static int +ecdsa_sign_setup(EC_KEY *ec, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp) +{ return 1; } -#endif /* ifdef MANAGMENT_EXTERNAL_KEY */ +/* EC_KEY_METHOD callback: sign_sig(). + * Sign the hash and return the result as a newly allocated ECDS_SIG + * struct or NULL on error. + */ +static ECDSA_SIG * +ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, const BIGNUM *in_kinv, + const BIGNUM *in_r, EC_KEY *ec) +{ + ECDSA_SIG *ecsig = NULL; + unsigned int len = ECDSA_size(ec); + struct gc_arena gc = gc_new(); + + unsigned char *buf = gc_malloc(len, false, &gc); + if (ecdsa_sign(0, dgst, dgstlen, buf, &len, NULL, NULL, ec) != 1) + { + goto out; + } + /* const char ** should be avoided: not up to us, so we cast our way through */ + ecsig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&buf, len); + +out: + gc_free(&gc); + return ecsig; +} + +static int +tls_ctx_use_external_ec_key(struct tls_root_ctx *ctx, EVP_PKEY *pkey) +{ + EC_KEY *ec = NULL; + EVP_PKEY *privkey = NULL; + EC_KEY_METHOD *ec_method; + + ASSERT(ctx); + + ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL()); + if (!ec_method) + { + goto err; + } + + /* Among init methods, we only need the finish method */ + EC_KEY_METHOD_set_init(ec_method, NULL, openvpn_extkey_ec_finish, NULL, NULL, NULL, NULL); + EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig); + + ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey)); + if (!ec) + { + EC_KEY_METHOD_free(ec_method); + goto err; + } + if (!EC_KEY_set_method(ec, ec_method)) + { + EC_KEY_METHOD_free(ec_method); + goto err; + } + /* from this point ec_method will get freed when ec is freed */ + + privkey = EVP_PKEY_new(); + if (!EVP_PKEY_assign_EC_KEY(privkey, ec)) + { + goto err; + } + /* from this point ec will get freed when privkey is freed */ + + if (!SSL_CTX_use_PrivateKey(ctx->ctx, privkey)) + { + ec = NULL; /* avoid double freeing it below */ + goto err; + } + + EVP_PKEY_free(privkey); /* this will down ref privkey and ec */ + return 1; + +err: + /* Reach here only when ec and privkey can be independenly freed */ + if (privkey) + { + EVP_PKEY_free(privkey); + } + if (ec) + { + EC_KEY_free(ec); + } + return 0; +} +#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */ + +int +tls_ctx_use_management_external_key(struct tls_root_ctx *ctx) +{ + int ret = 1; + + ASSERT(NULL != ctx); + + X509 *cert = SSL_CTX_get0_certificate(ctx->ctx); + + ASSERT(NULL != cert); + + /* get the public key */ + EVP_PKEY *pkey = X509_get0_pubkey(cert); + ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */ + + if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) + { + if (!tls_ctx_use_external_rsa_key(ctx, pkey)) + { + goto cleanup; + } + } +#if ((OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)) \ + || LIBRESSL_VERSION_NUMBER > 0x2090000fL) \ + && !defined(OPENSSL_NO_EC) + else if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) + { + if (!tls_ctx_use_external_ec_key(ctx, pkey)) + { + goto cleanup; + } + } + else + { + crypto_msg(M_WARN, "management-external-key requires an RSA or EC certificate"); + goto cleanup; + } +#else /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */ + else + { + crypto_msg(M_WARN, "management-external-key requires an RSA certificate"); + goto cleanup; + } +#endif /* OPENSSL_VERSION_NUMBER > 1.1.0 dev && !defined(OPENSSL_NO_EC) */ + + ret = 0; +cleanup: + if (ret) + { + crypto_msg(M_FATAL, "Cannot enable SSL external private key capability"); + } + return ret; +} + +#endif /* ifdef ENABLE_MANAGEMENT */ static int sk_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b) @@ -1293,9 +1529,7 @@ sk_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b) void tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, - const char *ca_file_inline, - const char *ca_path, bool tls_server - ) + bool ca_file_inline, const char *ca_path, bool tls_server) { STACK_OF(X509_INFO) *info_stack = NULL; STACK_OF(X509_NAME) *cert_names = NULL; @@ -1316,9 +1550,9 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, /* Try to add certificates and CRLs from ca_file */ if (ca_file) { - if (!strcmp(ca_file, INLINE_FILE_TAG) && ca_file_inline) + if (ca_file_inline) { - in = BIO_new_mem_buf((char *)ca_file_inline, -1); + in = BIO_new_mem_buf((char *)ca_file, -1); } else { @@ -1390,11 +1624,11 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, { crypto_msg(M_WARN, "Cannot load CA certificate file %s (entry %d did not validate)", - np(ca_file), added); + print_key_filename(ca_file, ca_file_inline), + added); } prev = cnum; } - } sk_X509_INFO_pop_free(info_stack, X509_INFO_free); } @@ -1408,7 +1642,7 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, { crypto_msg(M_FATAL, "Cannot load CA certificate file %s (no entries were read)", - np(ca_file)); + print_key_filename(ca_file, ca_file_inline)); } if (tls_server) @@ -1418,7 +1652,8 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, { crypto_msg(M_FATAL, "Cannot load CA certificate file %s (only %d " "of %d entries were valid X509 names)", - np(ca_file), cnum, added); + print_key_filename(ca_file, ca_file_inline), cnum, + added); } } @@ -1446,13 +1681,12 @@ tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, void tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file, - const char *extra_certs_file_inline - ) + bool extra_certs_file_inline) { BIO *in; - if (!strcmp(extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline) + if (extra_certs_file_inline) { - in = BIO_new_mem_buf((char *)extra_certs_file_inline, -1); + in = BIO_new_mem_buf((char *)extra_certs_file, -1); } else { @@ -1461,7 +1695,10 @@ tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file, if (in == NULL) { - crypto_msg(M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); + crypto_msg(M_FATAL, "Cannot load extra-certs file: %s", + print_key_filename(extra_certs_file, + extra_certs_file_inline)); + } else { @@ -1529,8 +1766,8 @@ bio_debug_data(const char *mode, BIO *bio, const uint8_t *buf, int len, const ch if (len > 0) { open_biofp(); - fprintf(biofp, "BIO_%s %s time=" time_format " bio=" ptr_format " len=%d data=%s\n", - mode, desc, time(NULL), (ptr_type)bio, len, format_hex(buf, len, 0, &gc)); + fprintf(biofp, "BIO_%s %s time=%" PRIi64 " bio=" ptr_format " len=%d data=%s\n", + mode, desc, (int64_t)time(NULL), (ptr_type)bio, len, format_hex(buf, len, 0, &gc)); fflush(biofp); } gc_free(&gc); @@ -1540,8 +1777,8 @@ static void bio_debug_oc(const char *mode, BIO *bio) { open_biofp(); - fprintf(biofp, "BIO %s time=" time_format " bio=" ptr_format "\n", - mode, time(NULL), (ptr_type)bio); + fprintf(biofp, "BIO %s time=%" PRIi64 " bio=" ptr_format "\n", + mode, (int64_t)time(NULL), (ptr_type)bio); fflush(biofp); } @@ -1848,7 +2085,7 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix) { EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); const EC_GROUP *group = EC_KEY_get0_group(ec); - const char* curve; + const char *curve; int nid = EC_GROUP_get_curve_name(group); if (nid == 0 || (curve = OBJ_nid2sn(nid)) == NULL) @@ -1873,7 +2110,7 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix) void show_available_tls_ciphers_list(const char *cipher_list, const char *tls_cert_profile, - const bool tls13) + bool tls13) { struct tls_root_ctx tls_ctx; @@ -1883,10 +2120,11 @@ show_available_tls_ciphers_list(const char *cipher_list, crypto_msg(M_FATAL, "Cannot create SSL_CTX object"); } -#if (OPENSSL_VERSION_NUMBER >= 0x1010100fL) && defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) +#if defined(TLS1_3_VERSION) if (tls13) { - SSL_CTX_set_min_proto_version(tls_ctx.ctx, TLS1_3_VERSION); + SSL_CTX_set_min_proto_version(tls_ctx.ctx, + openssl_tls_version(TLS_VER_1_3)); tls_ctx_restrict_ciphers_tls13(&tls_ctx, cipher_list); } else @@ -1904,12 +2142,13 @@ show_available_tls_ciphers_list(const char *cipher_list, crypto_msg(M_FATAL, "Cannot create SSL object"); } -#if (OPENSSL_VERSION_NUMBER < 0x1010000fL) +#if (OPENSSL_VERSION_NUMBER < 0x1010000fL) \ + || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER <= 0x2090000fL) STACK_OF(SSL_CIPHER) *sk = SSL_get_ciphers(ssl); #else STACK_OF(SSL_CIPHER) *sk = SSL_get1_supported_ciphers(ssl); #endif - for (int i=0;i < sk_SSL_CIPHER_num(sk);i++) + for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++) { const SSL_CIPHER *c = sk_SSL_CIPHER_value(sk, i); @@ -1920,7 +2159,7 @@ show_available_tls_ciphers_list(const char *cipher_list, if (tls13) { - printf("%s\n", cipher_name); + printf("%s\n", cipher_name); } else if (NULL == pair) { @@ -1947,6 +2186,8 @@ show_available_tls_ciphers_list(const char *cipher_list, void show_available_curves(void) { + printf("Consider using openssl 'ecparam -list_curves' as\n" + "alternative to running this command.\n"); #ifndef OPENSSL_NO_EC EC_builtin_curve *curves = NULL; size_t crv_len = 0; @@ -1956,7 +2197,7 @@ show_available_curves(void) ALLOC_ARRAY(curves, EC_builtin_curve, crv_len); if (EC_get_builtin_curves(curves, crv_len)) { - printf("Available Elliptic curves:\n"); + printf("\nAvailable Elliptic curves/groups:\n"); for (n = 0; n < crv_len; n++) { const char *sname; @@ -2008,7 +2249,7 @@ get_highest_preference_tls_cipher(char *buf, int size) const char * get_ssl_library_version(void) { - return SSLeay_version(SSLEAY_VERSION); + return OpenSSL_version(OPENSSL_VERSION); } -#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */ +#endif /* defined(ENABLE_CRYPTO_OPENSSL) */ |