diff options
Diffstat (limited to 'openvpn/src/openvpn/ssl_openssl.c')
-rw-r--r-- | openvpn/src/openvpn/ssl_openssl.c | 1327 |
1 files changed, 0 insertions, 1327 deletions
diff --git a/openvpn/src/openvpn/ssl_openssl.c b/openvpn/src/openvpn/ssl_openssl.c deleted file mode 100644 index f0796526..00000000 --- a/openvpn/src/openvpn/ssl_openssl.c +++ /dev/null @@ -1,1327 +0,0 @@ -/* - * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> - * - * 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 Control Channel OpenSSL Backend - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#elif defined(_MSC_VER) -#include "config-msvc.h" -#endif - -#include "syshead.h" - -#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL) - -#include "errlevel.h" -#include "buffer.h" -#include "misc.h" -#include "manage.h" -#include "memdbg.h" -#include "ssl_backend.h" -#include "ssl_common.h" -#include "base64.h" - -#ifdef ENABLE_CRYPTOAPI -#include "cryptoapi.h" -#endif - -#include "ssl_verify_openssl.h" - -#include <openssl/err.h> -#include <openssl/pkcs12.h> -#include <openssl/x509.h> -#include <openssl/crypto.h> - -/* - * Allocate space in SSL objects in which to store a struct tls_session - * pointer back to parent. - * - */ - -int mydata_index; /* GLOBAL */ - -void -tls_init_lib() -{ - SSL_library_init(); -#ifndef ENABLE_SMALL - SSL_load_error_strings(); -#endif - OpenSSL_add_all_algorithms (); - - mydata_index = SSL_get_ex_new_index(0, "struct session *", NULL, NULL, NULL); - ASSERT (mydata_index >= 0); -} - -void -tls_free_lib() -{ - EVP_cleanup(); -#ifndef ENABLE_SMALL - ERR_free_strings(); -#endif -} - -void -tls_clear_error() -{ - ERR_clear_error (); -} - -void -tls_ctx_server_new(struct tls_root_ctx *ctx) -{ - ASSERT(NULL != ctx); - - ctx->ctx = SSL_CTX_new (SSLv23_server_method ()); - - if (ctx->ctx == NULL) - msg (M_SSLERR, "SSL_CTX_new SSLv23_server_method"); -} - -void -tls_ctx_client_new(struct tls_root_ctx *ctx) -{ - ASSERT(NULL != ctx); - - ctx->ctx = SSL_CTX_new (SSLv23_client_method ()); - - if (ctx->ctx == NULL) - msg (M_SSLERR, "SSL_CTX_new SSLv23_client_method"); -} - -void -tls_ctx_free(struct tls_root_ctx *ctx) -{ - ASSERT(NULL != ctx); - if (NULL != ctx->ctx) - SSL_CTX_free (ctx->ctx); - ctx->ctx = NULL; -} - -bool tls_ctx_initialised(struct tls_root_ctx *ctx) -{ - ASSERT(NULL != ctx); - return NULL != ctx->ctx; -} - -/* - * Print debugging information on SSL/TLS session negotiation. - */ - -#ifndef INFO_CALLBACK_SSL_CONST -#define INFO_CALLBACK_SSL_CONST const -#endif -static void -info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret) -{ - if (where & SSL_CB_LOOP) - { - dmsg (D_HANDSHAKE_VERBOSE, "SSL state (%s): %s", - where & SSL_ST_CONNECT ? "connect" : - where & SSL_ST_ACCEPT ? "accept" : - "undefined", SSL_state_string_long (s)); - } - else if (where & SSL_CB_ALERT) - { - dmsg (D_HANDSHAKE_VERBOSE, "SSL alert (%s): %s: %s", - where & SSL_CB_READ ? "read" : "write", - SSL_alert_type_string_long (ret), - SSL_alert_desc_string_long (ret)); - } -} - -/* - * Return maximum TLS version supported by local OpenSSL library. - * Assume that presence of SSL_OP_NO_TLSvX macro indicates that - * TLSvX is supported. - */ -int -tls_version_max(void) -{ -#if defined(SSL_OP_NO_TLSv1_2) - return TLS_VER_1_2; -#elif defined(SSL_OP_NO_TLSv1_1) - return TLS_VER_1_1; -#else - return TLS_VER_1_0; -#endif -} - -void -tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) -{ - ASSERT(NULL != ctx); - - /* process SSL options including minimum TLS version we will accept from peer */ - { - long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; - const int tls_version_min = (ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK; - if (tls_version_min > TLS_VER_1_0) - sslopt |= SSL_OP_NO_TLSv1; -#ifdef SSL_OP_NO_TLSv1_1 - if (tls_version_min > TLS_VER_1_1) - sslopt |= SSL_OP_NO_TLSv1_1; -#endif -#ifdef SSL_OP_NO_TLSv1_2 - if (tls_version_min > TLS_VER_1_2) - sslopt |= SSL_OP_NO_TLSv1_2; -#endif - SSL_CTX_set_options (ctx->ctx, sslopt); - } - - SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF); - SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback); - - /* Require peer certificate verification */ -#if P2MP_SERVER - if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) - { - msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " - "--client-cert-not-required may accept clients which do not present " - "a certificate"); - } - else -#endif - SSL_CTX_set_verify (ctx->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - verify_callback); - - SSL_CTX_set_info_callback (ctx->ctx, info_callback); -} - -void -tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) -{ - if (ciphers == NULL) - { - /* Use sane default */ - if(!SSL_CTX_set_cipher_list(ctx->ctx, "DEFAULT:!EXP")) - msg(M_SSLERR, "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; - - const char *current_cipher; - size_t current_cipher_len; - - 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) { - end_of_cipher += strcspn(&ciphers[begin_of_cipher], ":"); - cipher_pair = tls_get_cipher_name_pair(&ciphers[begin_of_cipher], end_of_cipher - begin_of_cipher); - - if (NULL == cipher_pair) - { - // No translation found, use original - current_cipher = &ciphers[begin_of_cipher]; - current_cipher_len = end_of_cipher - begin_of_cipher; - - // Issue warning on missing translation - // %.*s format specifier expects length of type int, so guarantee - // that length is small enough and cast to int. - msg (M_WARN, "No valid translation found for TLS cipher '%.*s'", - constrain_int(current_cipher_len, 0, 256), current_cipher); - } - else - { - // Use OpenSSL name - current_cipher = cipher_pair->openssl_name; - current_cipher_len = strlen(current_cipher); - - if (end_of_cipher - begin_of_cipher == current_cipher_len && - 0 == memcmp (&ciphers[begin_of_cipher], cipher_pair->openssl_name, end_of_cipher - begin_of_cipher)) - { - // Non-IANA name used, show warning - msg (M_WARN, "Deprecated TLS cipher name '%s', please use IANA name '%s'", cipher_pair->openssl_name, cipher_pair->iana_name); - } - } - - // Make sure new cipher name fits in cipher string - if (((sizeof(openssl_ciphers)-1) - openssl_ciphers_len) < current_cipher_len) { - msg(M_SSLERR, "Failed to set restricted TLS cipher list, too long (>%d).", (int)sizeof(openssl_ciphers)-1); - } - - // Concatenate cipher name to OpenSSL cipher string - memcpy(&openssl_ciphers[openssl_ciphers_len], current_cipher, current_cipher_len); - openssl_ciphers_len += current_cipher_len; - openssl_ciphers[openssl_ciphers_len] = ':'; - openssl_ciphers_len++; - - end_of_cipher++; - } - - if (openssl_ciphers_len > 0) - openssl_ciphers[openssl_ciphers_len-1] = '\0'; - - // Set OpenSSL cipher list - if(!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers)) - msg(M_SSLERR, "Failed to set restricted TLS cipher list: %s", openssl_ciphers); -} - -void -tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, - const char *dh_file_inline - ) -{ - DH *dh; - BIO *bio; - - ASSERT(NULL != ctx); - - if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_file_inline) - { - if (!(bio = BIO_new_mem_buf ((char *)dh_file_inline, -1))) - msg (M_SSLERR, "Cannot open memory BIO for inline DH parameters"); - } - else - { - /* Get Diffie Hellman Parameters */ - if (!(bio = BIO_new_file (dh_file, "r"))) - msg (M_SSLERR, "Cannot open %s for DH parameters", dh_file); - } - - dh = PEM_read_bio_DHparams (bio, NULL, NULL, NULL); - BIO_free (bio); - - if (!dh) - msg (M_SSLERR, "Cannot load DH parameters from %s", dh_file); - if (!SSL_CTX_set_tmp_dh (ctx->ctx, dh)) - msg (M_SSLERR, "SSL_CTX_set_tmp_dh"); - - msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with %d bit key", - 8 * DH_size (dh)); - - DH_free (dh); -} - -int -tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, - const char *pkcs12_file_inline, - bool load_ca_file - ) -{ - FILE *fp; - EVP_PKEY *pkey; - X509 *cert; - STACK_OF(X509) *ca = NULL; - PKCS12 *p12; - int i; - char password[256]; - - ASSERT(NULL != ctx); - - if (!strcmp (pkcs12_file, INLINE_FILE_TAG) && 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)); - ASSERT(b64 && bio); - BIO_push(b64, bio); - p12 = d2i_PKCS12_bio(b64, NULL); - if (!p12) - msg(M_SSLERR, "Error reading inline PKCS#12 file"); - BIO_free(b64); - BIO_free(bio); - } - else - { - /* Load the PKCS #12 file */ - if (!(fp = platform_fopen(pkcs12_file, "rb"))) - msg(M_SSLERR, "Error opening file %s", pkcs12_file); - p12 = d2i_PKCS12_fp(fp, NULL); - fclose(fp); - if (!p12) - msg(M_SSLERR, "Error reading PKCS#12 file %s", pkcs12_file); - } - - /* Parse the PKCS #12 file */ - if (!PKCS12_parse(p12, "", &pkey, &cert, &ca)) - { - pem_password_callback (password, sizeof(password) - 1, 0, NULL); - /* Reparse the PKCS #12 file with password */ - ca = NULL; - if (!PKCS12_parse(p12, password, &pkey, &cert, &ca)) - { -#ifdef ENABLE_MANAGEMENT - if (management && (ERR_GET_REASON (ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE)) - management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); -#endif - PKCS12_free(p12); - return 1; - } - } - PKCS12_free(p12); - - /* Load Certificate */ - if (!SSL_CTX_use_certificate (ctx->ctx, cert)) - msg (M_SSLERR, "Cannot use certificate"); - - /* Load Private Key */ - if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey)) - msg (M_SSLERR, "Cannot use private key"); - warn_if_group_others_accessible (pkcs12_file); - - /* Check Private Key */ - if (!SSL_CTX_check_private_key (ctx->ctx)) - msg (M_SSLERR, "Private key does not match the certificate"); - - /* Set Certificate Verification chain */ - if (load_ca_file) - { - /* Add CAs from PKCS12 to the cert store and mark them as trusted. - * They're also used to fill in the chain of intermediate certs as - * necessary. - */ - if (ca && sk_X509_num(ca)) - { - for (i = 0; i < sk_X509_num(ca); i++) - { - if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) - msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)"); - if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i))) - msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); - } - } - } else { - /* If trusted CA certs were loaded from a PEM file, and we ignore the - * ones in PKCS12, do load PKCS12-provided certs to the client extra - * certs chain just in case they include intermediate CAs needed to - * prove my identity to the other end. This does not make them trusted. - */ - if (ca && sk_X509_num(ca)) - { - for (i = 0; i < sk_X509_num(ca); i++) - { - if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i))) - msg (M_SSLERR, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)"); - } - } - } - return 0; -} - -#ifdef ENABLE_CRYPTOAPI -void -tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) -{ - ASSERT(NULL != ctx); - - /* Load Certificate and Private Key */ - if (!SSL_CTX_use_CryptoAPI_certificate (ctx->ctx, cryptoapi_cert)) - msg (M_SSLERR, "Cannot load certificate \"%s\" from Microsoft Certificate Store", - cryptoapi_cert); -} -#endif /* WIN32 */ - -static void -tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio) -{ - X509 *cert; - for (;;) - { - cert = NULL; - if (!PEM_read_bio_X509 (bio, &cert, 0, NULL)) /* takes ownership of cert */ - break; - if (!cert) - msg (M_SSLERR, "Error reading extra certificate"); - if (SSL_CTX_add_extra_chain_cert(ctx->ctx, cert) != 1) - msg (M_SSLERR, "Error adding extra certificate"); - } -} - -/* 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 - ) -{ - 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) - in = BIO_new_mem_buf ((char *)cert_file_inline, -1); - else - in = BIO_new_file (cert_file, "r"); - - if (in == NULL) - { - SSLerr (SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); - goto end; - } - - x = PEM_read_bio_X509 (in, NULL, ctx->ctx->default_passwd_callback, - ctx->ctx->default_passwd_callback_userdata); - if (x == NULL) - { - SSLerr (SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); - goto end; - } - - ret = SSL_CTX_use_certificate (ctx->ctx, x); - if (ret) - tls_ctx_add_extra_certs (ctx, in); - -end: - if (!ret) - { - if (inline_file) - msg (M_SSLERR, "Cannot load inline certificate file"); - else - msg (M_SSLERR, "Cannot load certificate file %s", cert_file); - } - - if (in != NULL) - BIO_free(in); - if (x509) - *x509 = x; - else 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); -} - -void -tls_ctx_free_cert_file (X509 *x509) -{ - X509_free(x509); -} - -int -tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, - const char *priv_key_file_inline - ) -{ - SSL_CTX *ssl_ctx = NULL; - BIO *in = NULL; - EVP_PKEY *pkey = NULL; - int ret = 1; - - ASSERT(NULL != ctx); - - ssl_ctx = ctx->ctx; - - if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline) - in = BIO_new_mem_buf ((char *)priv_key_file_inline, -1); - else - in = BIO_new_file (priv_key_file, "r"); - - if (!in) - goto end; - - pkey = PEM_read_bio_PrivateKey (in, NULL, - ssl_ctx->default_passwd_callback, - ssl_ctx->default_passwd_callback_userdata); - if (!pkey) - goto end; - - if (!SSL_CTX_use_PrivateKey (ssl_ctx, pkey)) - { -#ifdef ENABLE_MANAGEMENT - if (management && (ERR_GET_REASON (ERR_peek_error()) == EVP_R_BAD_DECRYPT)) - management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); -#endif - msg (M_WARN|M_SSL, "Cannot load private key file %s", priv_key_file); - goto end; - } - warn_if_group_others_accessible (priv_key_file); - - /* Check Private Key */ - if (!SSL_CTX_check_private_key (ssl_ctx)) - msg (M_SSLERR, "Private key does not match the certificate"); - ret = 0; - -end: - if (pkey) - EVP_PKEY_free (pkey); - if (in) - BIO_free (in); - return ret; -} - -#ifdef MANAGMENT_EXTERNAL_KEY - -/* encrypt */ -static int -rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - ASSERT(0); - return -1; -} - -/* verify arbitrary data */ -static int -rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - ASSERT(0); - return -1; -} - -/* decrypt */ -static int -rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - ASSERT(0); - return -1; -} - -/* called at RSA_free */ -static int -rsa_finish(RSA *rsa) -{ - free ((void*)rsa->meth); - rsa->meth = NULL; - return 1; -} - -/* sign arbitrary data */ -static int -rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - /* optional app data in rsa->meth->app_data; */ - char *in_b64 = NULL; - char *out_b64 = NULL; - int ret = -1; - int len; - - if (padding != RSA_PKCS1_PADDING) - { - RSAerr (RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); - goto done; - } - - /* convert 'from' to base64 */ - if (openvpn_base64_encode (from, flen, &in_b64) <= 0) - goto done; - - /* call MI for signature */ - if (management) - out_b64 = management_query_rsa_sig (management, in_b64); - if (!out_b64) - goto done; - - /* decode base64 signature to binary */ - len = RSA_size(rsa); - ret = openvpn_base64_decode (out_b64, to, len); - - /* verify length */ - if (ret != len) - ret = -1; - - done: - if (in_b64) - free (in_b64); - if (out_b64) - free (out_b64); - return ret; -} - -int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline) -{ - 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); - - /* 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; - - /* allocate RSA object */ - rsa = RSA_new(); - if (rsa == NULL) - { - SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); - goto err; - } - - /* get the public key */ - ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */ - pub_rsa = cert->cert_info->key->pkey->pkey.rsa; - - /* initialize RSA object */ - rsa->n = BN_dup(pub_rsa->n); - rsa->flags |= RSA_FLAG_EXT_PKEY; - if (!RSA_set_method(rsa, rsa_meth)) - goto err; - - /* bind our custom RSA object to ssl_ctx */ - if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) - goto err; - - X509_free(cert); - RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ - return 1; - - err: - if (cert) - X509_free(cert); - if (rsa) - RSA_free(rsa); - else - { - if (rsa_meth) - free(rsa_meth); - } - msg (M_SSLERR, "Cannot enable SSL external private key capability"); - return 0; -} - -#endif - -static int -sk_x509_name_cmp(const X509_NAME * const *a, const X509_NAME * const *b) -{ - return X509_NAME_cmp (*a, *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 - ) -{ - STACK_OF(X509_INFO) *info_stack = NULL; - STACK_OF(X509_NAME) *cert_names = NULL; - X509_LOOKUP *lookup = NULL; - X509_STORE *store = NULL; - X509_NAME *xn = NULL; - BIO *in = NULL; - int i, added = 0, prev = 0; - - ASSERT(NULL != ctx); - - store = SSL_CTX_get_cert_store(ctx->ctx); - if (!store) - msg(M_SSLERR, "Cannot get certificate store (SSL_CTX_get_cert_store)"); - - /* Try to add certificates and CRLs from ca_file */ - if (ca_file) - { - if (!strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline) - in = BIO_new_mem_buf ((char *)ca_file_inline, -1); - else - in = BIO_new_file (ca_file, "r"); - - if (in) - info_stack = PEM_X509_INFO_read_bio (in, NULL, NULL, NULL); - - if (info_stack) - { - for (i = 0; i < sk_X509_INFO_num (info_stack); i++) - { - X509_INFO *info = sk_X509_INFO_value (info_stack, i); - if (info->crl) - X509_STORE_add_crl (store, info->crl); - - if (tls_server && !info->x509) - { - msg (M_SSLERR, "X509 name was missing in TLS mode"); - } - - if (info->x509) - { - X509_STORE_add_cert (store, info->x509); - added++; - - if (!tls_server) - continue; - - /* Use names of CAs as a client CA list */ - if (cert_names == NULL) - { - cert_names = sk_X509_NAME_new (sk_x509_name_cmp); - if (!cert_names) - continue; - } - - xn = X509_get_subject_name (info->x509); - if (!xn) - continue; - - /* Don't add duplicate CA names */ - if (sk_X509_NAME_find (cert_names, xn) == -1) - { - xn = X509_NAME_dup (xn); - if (!xn) - continue; - sk_X509_NAME_push (cert_names, xn); - } - } - - if (tls_server) { - int cnum = sk_X509_NAME_num (cert_names); - if (cnum != (prev + 1)) { - msg (M_WARN, "Cannot load CA certificate file %s (entry %d did not validate)", np(ca_file), added); - } - prev = cnum; - } - - } - sk_X509_INFO_pop_free (info_stack, X509_INFO_free); - } - - if (tls_server) - SSL_CTX_set_client_CA_list (ctx->ctx, cert_names); - - if (!added) - msg (M_SSLERR, "Cannot load CA certificate file %s (no entries were read)", np(ca_file)); - - if (tls_server) { - int cnum = sk_X509_NAME_num (cert_names); - if (cnum != added) - msg (M_SSLERR, "Cannot load CA certificate file %s (only %d of %d entries were valid X509 names)", np(ca_file), cnum, added); - } - - if (in) - BIO_free (in); - } - - /* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */ - if (ca_path) - { - lookup = X509_STORE_add_lookup (store, X509_LOOKUP_hash_dir ()); - if (lookup && X509_LOOKUP_add_dir (lookup, ca_path, X509_FILETYPE_PEM)) - msg(M_WARN, "WARNING: experimental option --capath %s", ca_path); - else - msg(M_SSLERR, "Cannot add lookup at --capath %s", ca_path); -#if OPENSSL_VERSION_NUMBER >= 0x00907000L - X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); -#else - msg(M_WARN, "WARNING: this version of OpenSSL cannot handle CRL files in capath"); -#endif - } -} - -void -tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file, - const char *extra_certs_file_inline - ) -{ - BIO *in; - if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline) - in = BIO_new_mem_buf ((char *)extra_certs_file_inline, -1); - else - in = BIO_new_file (extra_certs_file, "r"); - - if (in == NULL) - msg (M_SSLERR, "Cannot load extra-certs file: %s", extra_certs_file); - else - tls_ctx_add_extra_certs (ctx, in); - - BIO_free (in); -} - -/* ************************************** - * - * Key-state specific functions - * - ***************************************/ -/* - * - * BIO functions - * - */ - -#ifdef BIO_DEBUG - -#warning BIO_DEBUG defined - -static FILE *biofp; /* GLOBAL */ -static bool biofp_toggle; /* GLOBAL */ -static time_t biofp_last_open; /* GLOBAL */ -static const int biofp_reopen_interval = 600; /* GLOBAL */ - -static void -close_biofp() -{ - if (biofp) - { - ASSERT (!fclose (biofp)); - biofp = NULL; - } -} - -static void -open_biofp() -{ - const time_t current = time (NULL); - const pid_t pid = getpid (); - - if (biofp_last_open + biofp_reopen_interval < current) - close_biofp(); - if (!biofp) - { - char fn[256]; - openvpn_snprintf(fn, sizeof(fn), "bio/%d-%d.log", pid, biofp_toggle); - biofp = fopen (fn, "w"); - ASSERT (biofp); - biofp_last_open = time (NULL); - biofp_toggle ^= 1; - } -} - -static void -bio_debug_data (const char *mode, BIO *bio, const uint8_t *buf, int len, const char *desc) -{ - struct gc_arena gc = gc_new (); - 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)); - fflush (biofp); - } - gc_free (&gc); -} - -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); - fflush (biofp); -} - -#endif - -/* - * OpenVPN's interface to SSL/TLS authentication, - * encryption, and decryption is exclusively - * through "memory BIOs". - */ -static BIO * -getbio (BIO_METHOD * type, const char *desc) -{ - BIO *ret; - ret = BIO_new (type); - if (!ret) - msg (M_SSLERR, "Error creating %s BIO", desc); - return ret; -} - -/* - * Write to an OpenSSL BIO in non-blocking mode. - */ -static int -bio_write (BIO *bio, const uint8_t *data, int size, const char *desc) -{ - int i; - int ret = 0; - ASSERT (size >= 0); - if (size) - { - /* - * Free the L_TLS lock prior to calling BIO routines - * so that foreground thread can still call - * tls_pre_decrypt or tls_pre_encrypt, - * allowing tunnel packet forwarding to continue. - */ -#ifdef BIO_DEBUG - bio_debug_data ("write", bio, data, size, desc); -#endif - i = BIO_write (bio, data, size); - - if (i < 0) - { - if (BIO_should_retry (bio)) - { - ; - } - else - { - msg (D_TLS_ERRORS | M_SSL, "TLS ERROR: BIO write %s error", - desc); - ret = -1; - ERR_clear_error (); - } - } - else if (i != size) - { - msg (D_TLS_ERRORS | M_SSL, - "TLS ERROR: BIO write %s incomplete %d/%d", desc, i, size); - ret = -1; - ERR_clear_error (); - } - else - { /* successful write */ - dmsg (D_HANDSHAKE_VERBOSE, "BIO write %s %d bytes", desc, i); - ret = 1; - } - } - return ret; -} - -/* - * Inline functions for reading from and writing - * to BIOs. - */ - -static void -bio_write_post (const int status, struct buffer *buf) -{ - if (status == 1) /* success status return from bio_write? */ - { - memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */ - buf->len = 0; - } -} - -/* - * Read from an OpenSSL BIO in non-blocking mode. - */ -static int -bio_read (BIO *bio, struct buffer *buf, int maxlen, const char *desc) -{ - int i; - int ret = 0; - ASSERT (buf->len >= 0); - if (buf->len) - { - ; - } - else - { - int len = buf_forward_capacity (buf); - if (maxlen < len) - len = maxlen; - - /* - * BIO_read brackets most of the serious RSA - * key negotiation number crunching. - */ - i = BIO_read (bio, BPTR (buf), len); - - VALGRIND_MAKE_READABLE ((void *) &i, sizeof (i)); - -#ifdef BIO_DEBUG - bio_debug_data ("read", bio, BPTR (buf), i, desc); -#endif - if (i < 0) - { - if (BIO_should_retry (bio)) - { - ; - } - else - { - msg (D_TLS_ERRORS | M_SSL, "TLS_ERROR: BIO read %s error", - desc); - buf->len = 0; - ret = -1; - ERR_clear_error (); - } - } - else if (!i) - { - buf->len = 0; - } - else - { /* successful read */ - dmsg (D_HANDSHAKE_VERBOSE, "BIO read %s %d bytes", desc, i); - buf->len = i; - ret = 1; - VALGRIND_MAKE_READABLE ((void *) BPTR (buf), BLEN (buf)); - } - } - return ret; -} - -void -key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) -{ - ASSERT(NULL != ssl_ctx); - ASSERT(ks_ssl); - CLEAR (*ks_ssl); - - ks_ssl->ssl = SSL_new (ssl_ctx->ctx); - if (!ks_ssl->ssl) - msg (M_SSLERR, "SSL_new failed"); - - /* put session * in ssl object so we can access it - from verify callback*/ - SSL_set_ex_data (ks_ssl->ssl, mydata_index, session); - - ks_ssl->ssl_bio = getbio (BIO_f_ssl (), "ssl_bio"); - ks_ssl->ct_in = getbio (BIO_s_mem (), "ct_in"); - ks_ssl->ct_out = getbio (BIO_s_mem (), "ct_out"); - -#ifdef BIO_DEBUG - bio_debug_oc ("open ssl_bio", ks_ssl->ssl_bio); - bio_debug_oc ("open ct_in", ks_ssl->ct_in); - bio_debug_oc ("open ct_out", ks_ssl->ct_out); -#endif - - if (is_server) - SSL_set_accept_state (ks_ssl->ssl); - else - SSL_set_connect_state (ks_ssl->ssl); - - SSL_set_bio (ks_ssl->ssl, ks_ssl->ct_in, ks_ssl->ct_out); - BIO_set_ssl (ks_ssl->ssl_bio, ks_ssl->ssl, BIO_NOCLOSE); -} - -void key_state_ssl_free(struct key_state_ssl *ks_ssl) -{ - if (ks_ssl->ssl) { -#ifdef BIO_DEBUG - bio_debug_oc ("close ssl_bio", ks_ssl->ssl_bio); - bio_debug_oc ("close ct_in", ks_ssl->ct_in); - bio_debug_oc ("close ct_out", ks_ssl->ct_out); -#endif - BIO_free_all(ks_ssl->ssl_bio); - SSL_free (ks_ssl->ssl); - } -} - -int -key_state_write_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf) -{ - int ret = 0; - perf_push (PERF_BIO_WRITE_PLAINTEXT); - -#ifdef ENABLE_CRYPTO_OPENSSL - ASSERT (NULL != ks_ssl); - - ret = bio_write (ks_ssl->ssl_bio, BPTR(buf), BLEN(buf), - "tls_write_plaintext"); - bio_write_post (ret, buf); -#endif /* ENABLE_CRYPTO_OPENSSL */ - - perf_pop (); - return ret; -} - -int -key_state_write_plaintext_const (struct key_state_ssl *ks_ssl, const uint8_t *data, int len) -{ - int ret = 0; - perf_push (PERF_BIO_WRITE_PLAINTEXT); - - ASSERT (NULL != ks_ssl); - - ret = bio_write (ks_ssl->ssl_bio, data, len, "tls_write_plaintext_const"); - - perf_pop (); - return ret; -} - -int -key_state_read_ciphertext (struct key_state_ssl *ks_ssl, struct buffer *buf, - int maxlen) -{ - int ret = 0; - perf_push (PERF_BIO_READ_CIPHERTEXT); - - ASSERT (NULL != ks_ssl); - - ret = bio_read (ks_ssl->ct_out, buf, maxlen, "tls_read_ciphertext"); - - perf_pop (); - return ret; -} - -int -key_state_write_ciphertext (struct key_state_ssl *ks_ssl, struct buffer *buf) -{ - int ret = 0; - perf_push (PERF_BIO_WRITE_CIPHERTEXT); - - ASSERT (NULL != ks_ssl); - - ret = bio_write (ks_ssl->ct_in, BPTR(buf), BLEN(buf), "tls_write_ciphertext"); - bio_write_post (ret, buf); - - perf_pop (); - return ret; -} - -int -key_state_read_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf, - int maxlen) -{ - int ret = 0; - perf_push (PERF_BIO_READ_PLAINTEXT); - - ASSERT (NULL != ks_ssl); - - ret = bio_read (ks_ssl->ssl_bio, buf, maxlen, "tls_read_plaintext"); - - perf_pop (); - return ret; -} - -/* ************************************** - * - * Information functions - * - * Print information for the end user. - * - ***************************************/ -void -print_details (struct key_state_ssl * ks_ssl, const char *prefix) -{ - const SSL_CIPHER *ciph; - X509 *cert; - char s1[256]; - char s2[256]; - - s1[0] = s2[0] = 0; - ciph = SSL_get_current_cipher (ks_ssl->ssl); - openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s %s", - prefix, - SSL_get_version (ks_ssl->ssl), - SSL_CIPHER_get_version (ciph), - SSL_CIPHER_get_name (ciph)); - cert = SSL_get_peer_certificate (ks_ssl->ssl); - if (cert != NULL) - { - EVP_PKEY *pkey = X509_get_pubkey (cert); - if (pkey != NULL) - { - if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != 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 - && pkey->pkey.dsa->p != NULL) - { - openvpn_snprintf (s2, sizeof (s2), ", %d bit DSA", - BN_num_bits (pkey->pkey.dsa->p)); - } - EVP_PKEY_free (pkey); - } - X509_free (cert); - } - /* The SSL API does not allow us to look at temporary RSA/DH keys, - * otherwise we should print their lengths too */ - msg (D_HANDSHAKE, "%s%s", s1, s2); -} - -void -show_available_tls_ciphers (const char *cipher_list) -{ - struct tls_root_ctx tls_ctx; - SSL *ssl; - const char *cipher_name; - const tls_cipher_name_pair *pair; - int priority = 0; - - tls_ctx.ctx = SSL_CTX_new (SSLv23_method ()); - if (!tls_ctx.ctx) - msg (M_SSLERR, "Cannot create SSL_CTX object"); - - ssl = SSL_new (tls_ctx.ctx); - if (!ssl) - msg (M_SSLERR, "Cannot create SSL object"); - - tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); - - printf ("Available TLS Ciphers,\n"); - printf ("listed in order of preference:\n\n"); - while ((cipher_name = SSL_get_cipher_list (ssl, priority++))) - { - pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); - - if (NULL == pair) { - // No translation found, print warning - printf ("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n", cipher_name); - } else { - printf ("%s\n", pair->iana_name); - } - - } - printf ("\n"); - - SSL_free (ssl); - SSL_CTX_free (tls_ctx.ctx); -} - -void -get_highest_preference_tls_cipher (char *buf, int size) -{ - SSL_CTX *ctx; - SSL *ssl; - const char *cipher_name; - - ctx = SSL_CTX_new (SSLv23_method ()); - if (!ctx) - msg (M_SSLERR, "Cannot create SSL_CTX object"); - ssl = SSL_new (ctx); - if (!ssl) - msg (M_SSLERR, "Cannot create SSL object"); - - cipher_name = SSL_get_cipher_list (ssl, 0); - strncpynt (buf, cipher_name, size); - - SSL_free (ssl); - SSL_CTX_free (ctx); -} - -#endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL) */ |