From patchwork Sat Feb 10 11:49:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 231 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director3.mail.ord1d.rsapps.net ([172.27.255.8]) by backend31.mail.ord1d.rsapps.net (Dovecot) with LMTP id Q2xUHTd3f1rDUgAAgoeIoA for ; Sat, 10 Feb 2018 17:50:31 -0500 Received: from proxy5.mail.iad3a.rsapps.net ([172.27.255.8]) by director3.mail.ord1d.rsapps.net (Dovecot) with LMTP id sTcHADd3f1pcGwAAkXNnRw ; Sat, 10 Feb 2018 17:50:31 -0500 Received: from smtp45.gate.iad3a ([172.27.255.8]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy5.mail.iad3a.rsapps.net (Dovecot) with LMTP id 2yl5Ajd3f1qKFgAAhn5joQ ; Sat, 10 Feb 2018 17:50:31 -0500 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.34.181.88] Authentication-Results: smtp45.gate.iad3a.rsapps.net; iprev=pass policy.iprev="216.34.181.88"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=hansenpartnership.com; dmarc=fail (p=none; dis=none) header.from=hansenpartnership.com X-Classification-ID: ca825c68-0eb4-11e8-93a0-782bcb788684-1-1 Received: from [216.34.181.88] ([216.34.181.88:19830] helo=lists.sourceforge.net) by smtp45.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 3B/63-04369-5377F7A5; Sat, 10 Feb 2018 17:50:29 -0500 Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.89) (envelope-from ) id 1ekdxo-00066m-I9; Sat, 10 Feb 2018 22:49:44 +0000 Received: from sfi-mx-2.v28.ch3.sourceforge.com ([172.29.28.192] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1ekdxk-000660-SO for openvpn-devel@lists.sourceforge.net; Sat, 10 Feb 2018 22:49:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:Mime-Version:Content-Type :References:In-Reply-To:Date:To:From:Subject:Message-ID:Sender:Reply-To:Cc: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=G/PyDMY8TiZcQ8y4vlErc5Q8iAjKbSn/x58FH3flawQ=; b=jJo5Q42GsPxLpa2gogxYFKbx2a AqS+qXLY5cHE7adjd3GSTMixRBbdBPBJ2vadbGU9Q8Ao/4WLhXL2sIE68iIn/qwL1DkbcjozCABZY VgwfWctIiGhR2t3Q4flh27lTJqCTDGjdPLFKfZtPiN/GKXQPSzzyPPAZ5fFgWDZ6ukeQ=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:Mime-Version:Content-Type:References: In-Reply-To:Date:To:From:Subject:Message-ID:Sender:Reply-To:Cc:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=G/PyDMY8TiZcQ8y4vlErc5Q8iAjKbSn/x58FH3flawQ=; b=SkkYqM79gtzfasIpiWkJBZYBht fPrEv24P2u6bMXNCiwIJHmb8KH/8a6q2Eg7k52KEa3OM74Q3VhN/OxgPn4U/Iifb9bqk+D3aecTIk G+86E5SQP7qOY+6EKgST0LQKPdqFZcAtzv6eAGGZ/OstTJbBaM4AIPwSVKkLoFqnE8+0=; Received: from bedivere.hansenpartnership.com ([66.63.167.143]) by sfi-mx-2.v28.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) id 1ekdxj-0002e9-TS for openvpn-devel@lists.sourceforge.net; Sat, 10 Feb 2018 22:49:40 +0000 Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 1EF3C8EE0DD for ; Sat, 10 Feb 2018 14:49:34 -0800 (PST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6JY-pE-lAAbS for ; Sat, 10 Feb 2018 14:49:34 -0800 (PST) Received: from [153.66.254.194] (unknown [50.35.65.221]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by bedivere.hansenpartnership.com (Postfix) with ESMTPSA id CF54C8EE0BA for ; Sat, 10 Feb 2018 14:49:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=hansenpartnership.com; s=20151216; t=1518302973; bh=z5ITDjMQUoiDymdtdl2Jr4b5diqd/vg3oMBKahLrMgc=; h=Subject:From:To:Date:In-Reply-To:References:From; b=P+cGoZcoO1//oNOpy1VSrDlYoGQv/ajaeJIVm4ji7cf2plZNOrLxEMs/heBY5pA9+ 3zYJ36AOW7BGpb+WXXanPUaLwvSq0T6PaQlA6o4YohIimRnBSBDI1hyHieE0V/+KFc GO9d5XyLKywdpPLr5O0HrQ7oNB5jLM6rUCd1tD+4= Message-ID: <1518302972.3072.3.camel@HansenPartnership.com> From: James Bottomley To: openvpn-devel@lists.sourceforge.net Date: Sat, 10 Feb 2018 14:49:32 -0800 In-Reply-To: <1518302884.3072.1.camel@HansenPartnership.com> References: <1518302884.3072.1.camel@HansenPartnership.com> X-Mailer: Evolution 3.20.5 Mime-Version: 1.0 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1ekdxj-0002e9-TS Subject: [Openvpn-devel] [PATCH v4 1/2] openssl: add engine method for loading the key X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox As well as doing crypto acceleration, engines can also be used to load key files. If the engine is set, and the private key loading fails for bio methods, this patch makes openvpn try to get the engine to load the key. If that succeeds, we end up using an engine based key. This can be used with the openssl tpm engines to make openvpn use a TPM wrapped key file. Signed-off-by: James Bottomley --- v2: add better configuration guarding v4: - use crypto_msg() instead of raw openssl prints - remove ENGINE_init/finish(). Openvpn already initializes the engine so doing a second initialization is wrong. - don't clear the openssl errors from the BIO_read failure just in case they might be useful. - ad ui.h include for openssl 1.1 build failure --- src/openvpn/crypto_openssl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ src/openvpn/crypto_openssl.h | 12 ++++++++++ src/openvpn/ssl_openssl.c | 6 ++++- 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 4fb2f6d6..936cbb0d 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -63,6 +63,7 @@ #endif #if HAVE_OPENSSL_ENGINE +#include #include static bool engine_initialized = false; /* GLOBAL */ @@ -969,4 +970,56 @@ hmac_ctx_final(HMAC_CTX *ctx, uint8_t *dst) HMAC_Final(ctx, dst, &in_hmac_len); } +#if HAVE_OPENSSL_ENGINE +static int +ui_reader(UI *ui, UI_STRING *uis) +{ + SSL_CTX *ctx = UI_get0_user_data(ui); + + if (UI_get_string_type(uis) == UIT_PROMPT) { + pem_password_cb *cb = SSL_CTX_get_default_passwd_cb(ctx); + void *d = SSL_CTX_get_default_passwd_cb_userdata(ctx); + char password[64]; + + cb(password, sizeof(password), 0, d); + UI_set_result(ui, uis, password); + + return 1; + } + return 0; +} +#endif + +EVP_PKEY * +engine_load_key(const char *file, SSL_CTX *ctx) +{ +#if HAVE_OPENSSL_ENGINE + UI_METHOD *ui; + EVP_PKEY *pkey; + + if (!engine_persist) + return NULL; + + /* this will print out the error from BIO_read */ + crypto_msg(M_INFO, "PEM_read_bio failed, now trying engine method to load private key"); + + ui = UI_create_method("openvpn"); + if (!ui) { + crypto_msg(M_FATAL, "Engine UI creation failed"); + return NULL; + } + + UI_method_set_reader(ui, ui_reader); + + pkey = ENGINE_load_private_key(engine_persist, file, ui, ctx); + if (!pkey) + crypto_msg(M_FATAL, "Engine could not load key file"); + out: + UI_destroy_method(ui); + return pkey; +#else + return NULL; +#endif +} + #endif /* ENABLE_CRYPTO_OPENSSL */ diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h index 0a413705..98be36d5 100644 --- a/src/openvpn/crypto_openssl.h +++ b/src/openvpn/crypto_openssl.h @@ -101,5 +101,17 @@ void crypto_print_openssl_errors(const unsigned int flags); msg((flags), __VA_ARGS__); \ } while (false) +/** + * Load a key file from an engine + * + * @param file The engine file to load + * @param ui The UI method for the password prompt + * @param data The data to pass to the UI method + * + * @return The private key if successful or NULL if not + */ +EVP_PKEY * +engine_load_key(const char *file, SSL_CTX *ctx); + #endif /* CRYPTO_OPENSSL_H_ */ diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 26c1e608..76ce6939 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -907,7 +907,11 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx)); if (!pkey) { - goto end; + pkey = engine_load_key(priv_key_file, ctx->ctx); + if (!pkey) + { + goto end; + } } if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey)) From patchwork Sat Feb 10 11:50:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 232 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director5.mail.ord1d.rsapps.net ([172.27.255.57]) by backend31.mail.ord1d.rsapps.net (Dovecot) with LMTP id g2u5FE53f1ojXAAAgoeIoA for ; Sat, 10 Feb 2018 17:50:54 -0500 Received: from proxy9.mail.iad3a.rsapps.net ([172.27.255.57]) by director5.mail.ord1d.rsapps.net (Dovecot) with LMTP id fTCnBU53f1rhVQAAsdCWiw ; Sat, 10 Feb 2018 17:50:54 -0500 Received: from smtp48.gate.iad3a ([172.27.255.57]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy9.mail.iad3a.rsapps.net (Dovecot) with LMTP id arobDU53f1oJPgAAGuSQww ; Sat, 10 Feb 2018 17:50:54 -0500 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.34.181.88] Authentication-Results: smtp48.gate.iad3a.rsapps.net; iprev=pass policy.iprev="216.34.181.88"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=hansenpartnership.com; dmarc=fail (p=none; dis=none) header.from=hansenpartnership.com X-Classification-ID: d8ce7d2e-0eb4-11e8-b22e-0024e87f007c-1-1 Received: from [216.34.181.88] ([216.34.181.88:55576] helo=lists.sourceforge.net) by smtp48.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 16/2F-06506-D477F7A5; Sat, 10 Feb 2018 17:50:53 -0500 Received: from localhost ([127.0.0.1] helo=sfs-ml-2.v29.ch3.sourceforge.com) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.89) (envelope-from ) id 1ekdyQ-0001IN-Ke; Sat, 10 Feb 2018 22:50:22 +0000 Received: from sfi-mx-1.v28.ch3.sourceforge.com ([172.29.28.191] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1ekdyP-0001IH-Jk for openvpn-devel@lists.sourceforge.net; Sat, 10 Feb 2018 22:50:21 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:Mime-Version:Content-Type :References:In-Reply-To:Date:To:From:Subject:Message-ID:Sender:Reply-To:Cc: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=qtpxiCVn6uNxL5xrja4/nMBHv8gP8h45m47vMEZLgeY=; b=YSRHkogmfTqRng+cSgzy4uZCtP hhW6/0s0aHlr5v/ccd54IyCGN+Q3ocXnqIRwiyhI8ek582q+4Ze4uRUFzL1uYd5hUtgrAnJfscO/Q N9Pm1LlE4yzNmK4Eg1Mws5QXiogClfWlOuFGZbkc1mVFCX/cFnbPIPlZGfiXs84Eywdk=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:Mime-Version:Content-Type:References: In-Reply-To:Date:To:From:Subject:Message-ID:Sender:Reply-To:Cc:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=qtpxiCVn6uNxL5xrja4/nMBHv8gP8h45m47vMEZLgeY=; b=ZcJ931L26OV733XD0ym7zNAQxq KOBjVWNuxuoRxGKqMw/UnV0QksMUUUQQwAxwziSZpIF+mYxllSwGoUF118zjgeksJXrpzRNUnJivR ayFGElTul9brA1aeuXFwRwbsRRhR//3hlNTR7kd8uKbtTRFpddNldrgdzANXSjNGAqvU=; Received: from bedivere.hansenpartnership.com ([66.63.167.143]) by sfi-mx-1.v28.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) id 1ekdyL-0002q8-Tx for openvpn-devel@lists.sourceforge.net; Sat, 10 Feb 2018 22:50:21 +0000 Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 412998EE0DD for ; Sat, 10 Feb 2018 14:50:12 -0800 (PST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5xHbfJ4KnepJ for ; Sat, 10 Feb 2018 14:50:12 -0800 (PST) Received: from [153.66.254.194] (unknown [50.35.65.221]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by bedivere.hansenpartnership.com (Postfix) with ESMTPSA id C46F58EE0BA for ; Sat, 10 Feb 2018 14:50:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=hansenpartnership.com; s=20151216; t=1518303011; bh=eKTkFxQf0YRq3gMW8/dGiHMV842bPQvZt3DkCbW/h3I=; h=Subject:From:To:Date:In-Reply-To:References:From; b=utblfHNRtQA9KNwAlpATk8AbAvFNQupJHDObmFs6Pt70oQeajEc3K6wqRuFSWE+qV SKVh3TM6cxHtkTjrYK1dGxtlpZnuey5ji1BT/De9M+ebSUO81wBkPukGD17TPPIArv RHbod59fsI2r4g3zyYehbsu9OX+8MISnPrqpK0Cw= Message-ID: <1518303011.3072.4.camel@HansenPartnership.com> From: James Bottomley To: openvpn-devel@lists.sourceforge.net Date: Sat, 10 Feb 2018 14:50:11 -0800 In-Reply-To: <1518302884.3072.1.camel@HansenPartnership.com> References: <1518302884.3072.1.camel@HansenPartnership.com> X-Mailer: Evolution 3.20.5 Mime-Version: 1.0 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1ekdyL-0002q8-Tx Subject: [Openvpn-devel] [PATCH v4 2/2] Add unit tests for engine keys X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Testing engines is problematic, so one of the prerequisites built for the tests is a simple openssl engine that reads a non-standard PEM guarded key. The test is simply can we run a client/server configuration with the usual sample key replaced by an engine key. The trivial engine prints out some operations and we check for these in the log to make sure the engine was used to load the key and that it correctly got the password. Signed-off-by: James Bottomley --- v4: add OPENSSL_config(NULL) so debian checks will work v3: added this patch --- configure.ac | 2 + src/openvpn/crypto_openssl.c | 1 + tests/unit_tests/Makefile.am | 6 +- tests/unit_tests/engine-key/Makefile.am | 14 ++++ tests/unit_tests/engine-key/check_engine_keys.sh | 30 +++++++ tests/unit_tests/engine-key/libtestengine.c | 102 +++++++++++++++++++++++ tests/unit_tests/engine-key/openssl.cnf | 12 +++ 7 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 tests/unit_tests/engine-key/Makefile.am create mode 100755 tests/unit_tests/engine-key/check_engine_keys.sh create mode 100644 tests/unit_tests/engine-key/libtestengine.c create mode 100644 tests/unit_tests/engine-key/openssl.cnf diff --git a/configure.ac b/configure.ac index 2cbf3358..2f7ef8a0 100644 --- a/configure.ac +++ b/configure.ac @@ -1360,6 +1360,7 @@ AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"]) AM_CONDITIONAL([ENABLE_PLUGIN_AUTH_PAM], [test "${enable_plugin_auth_pam}" = "yes"]) AM_CONDITIONAL([ENABLE_PLUGIN_DOWN_ROOT], [test "${enable_plugin_down_root}" = "yes"]) AM_CONDITIONAL([HAVE_LD_WRAP_SUPPORT], [test "${have_ld_wrap_support}" = "yes"]) +AM_CONDITIONAL([OPENSSL_ENGINE], [test "${have_openssl_engine}" = "yes"]) sampledir="\$(docdir)/sample" AC_SUBST([plugindir]) @@ -1424,6 +1425,7 @@ AC_CONFIG_FILES([ tests/unit_tests/openvpn/Makefile tests/unit_tests/plugins/Makefile tests/unit_tests/plugins/auth-pam/Makefile + tests/unit_tests/engine-key/Makefile vendor/Makefile sample/Makefile ]) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 936cbb0d..558fdb46 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -92,6 +92,7 @@ setup_engine(const char *engine) { ENGINE *e = NULL; + OPENSSL_config(NULL); ENGINE_load_builtin_engines(); if (engine) diff --git a/tests/unit_tests/Makefile.am b/tests/unit_tests/Makefile.am index 31d37b89..648bd7a8 100644 --- a/tests/unit_tests/Makefile.am +++ b/tests/unit_tests/Makefile.am @@ -1,5 +1,9 @@ AUTOMAKE_OPTIONS = foreign +SUBDIRS = if CMOCKA_INITIALIZED -SUBDIRS = example_test openvpn plugins +SUBDIRS += example_test openvpn plugins +endif +if OPENSSL_ENGINE +SUBDIRS += engine-key endif diff --git a/tests/unit_tests/engine-key/Makefile.am b/tests/unit_tests/engine-key/Makefile.am new file mode 100644 index 00000000..f83bf817 --- /dev/null +++ b/tests/unit_tests/engine-key/Makefile.am @@ -0,0 +1,14 @@ +AUTOMAKE_OPTIONS = foreign + +check_LTLIBRARIES = libtestengine.la + +TESTS_ENVIRONMENT = srcdir="$(abs_srcdir)"; \ + top_builddir="$(top_builddir)"; \ + top_srcdir="$(top_srcdir)"; \ + export srcdir top_builddir top_srcdir; + +TESTS = check_engine_keys.sh + +libtestengine_la_SOURCES = libtestengine.c +libtestengine_la_LDFLAGS = -rpath /lib -avoid-version + diff --git a/tests/unit_tests/engine-key/check_engine_keys.sh b/tests/unit_tests/engine-key/check_engine_keys.sh new file mode 100755 index 00000000..c1ae59e6 --- /dev/null +++ b/tests/unit_tests/engine-key/check_engine_keys.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +OPENSSL_CONF="${srcdir}/openssl.cnf" +export OPENSSL_CONF + +password='AT3S4PASSWD' + +key="${srcdir}/client.key" +pwdfile="${srcdir}/passwd" + +# create an engine key for us +sed 's/PRIVATE KEY/TEST ENGINE KEY/' < ${top_srcdir}/sample/sample-keys/client.key > ${key} +echo "$password" > $pwdfile + +# note here we've induced a mismatch in the client key and the server +# cert which openvpn should report and die. Check that it does. Note +# also that this mismatch depends on openssl not openvpn, so it is +# somewhat fragile +${top_builddir}/src/openvpn/openvpn --cd ${top_srcdir}/sample --config sample-config-files/loopback-server --engine testengine --key ${key} --askpass $pwdfile > log.txt 2>&1 + +# first off check we died because of a key mismatch. If this doesn't +# pass, suspect openssl of returning different messages and update the +# test accordingly +grep -q 'X509_check_private_key:key values mismatch' log.txt || { echo "Key mismatch not detected"; exit 1; } + +# now look for the engine prints (these are under our control) +grep -q 'ENGINE: engine_init called' log.txt || { echo "Engine initialization not detected"; exit 1; } +grep -q 'ENGINE: engine_load_key called' log.txt || { echo "Key was not loaded from engine"; exit 1; } +grep -q "ENGINE: engine_load_key got password ${password}" log.txt || { echo "Key password was not retrieved by the engine"; exit 1; } +exit 0 diff --git a/tests/unit_tests/engine-key/libtestengine.c b/tests/unit_tests/engine-key/libtestengine.c new file mode 100644 index 00000000..4880223d --- /dev/null +++ b/tests/unit_tests/engine-key/libtestengine.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +static char *engine_id = "testengine"; +static char *engine_name = "Engine for testing openvpn engine key support"; + +static int is_initialized = 0; + +static int engine_init(ENGINE *e) +{ + is_initialized = 1; + fprintf(stderr, "ENGINE: engine_init called\n"); + return 1; +} + +static int engine_finish(ENGINE *e) +{ + fprintf(stderr, "ENGINE: engine_finsh called\n"); + is_initialized = 0; + return 1; +} + +static EVP_PKEY *engine_load_key(ENGINE *e, const char *key_id, + UI_METHOD *ui_method, void *cb_data) +{ + BIO *b; + EVP_PKEY *pkey; + PKCS8_PRIV_KEY_INFO *p8inf; + UI *ui; + char auth[256]; + int len; + + fprintf(stderr, "ENGINE: engine_load_key called\n"); + + if (!is_initialized) { + fprintf(stderr, "Load Key called without correct initialization\n"); + return NULL; + } + b = BIO_new_file(key_id, "r"); + if (!b) { + fprintf(stderr, "File %s does not exist or cannot be read\n", key_id); + return 0; + } + /* Basically read an EVP_PKEY private key file with different + * PEM guards --- we are a test engine */ + p8inf = PEM_ASN1_read_bio((d2i_of_void *)d2i_PKCS8_PRIV_KEY_INFO, + "TEST ENGINE KEY", b, + NULL, NULL, NULL); + BIO_free(b); + if (!p8inf) { + fprintf(stderr, "Failed to read engine private key\n"); + return NULL; + } + pkey = EVP_PKCS82PKEY(p8inf); + + /* now we have a private key, pretend it had a password + * this verifies the password makes it through openvpn OK */ + ui = UI_new(); + + if (ui_method) + UI_set_method(ui, ui_method); + + UI_add_user_data(ui, cb_data); + + if (UI_add_input_string(ui, "enter test engine key", + UI_INPUT_FLAG_DEFAULT_PWD, + auth, 0, sizeof(auth)) == 0) { + fprintf(stderr, "UI_add_input_string failed\n"); + goto out; + } + + if (UI_process(ui)) { + fprintf(stderr, "UI_process failed\n"); + goto out; + } + + fprintf(stderr, "ENGINE: engine_load_key got password %s\n", auth); + + out: + UI_free(ui); + + return pkey; +} + + +static int engine_bind_fn(ENGINE *e, const char *id) +{ + if (id && strcmp(id, engine_id) != 0) + return 0; + if (!ENGINE_set_id(e, engine_id) || + !ENGINE_set_name(e, engine_name) || + !ENGINE_set_init_function(e, engine_init) || + !ENGINE_set_finish_function(e, engine_finish) || + !ENGINE_set_load_privkey_function(e, engine_load_key)) + return 0; + return 1; +} + +IMPLEMENT_DYNAMIC_CHECK_FN() +IMPLEMENT_DYNAMIC_BIND_FN(engine_bind_fn) diff --git a/tests/unit_tests/engine-key/openssl.cnf b/tests/unit_tests/engine-key/openssl.cnf new file mode 100644 index 00000000..53200c46 --- /dev/null +++ b/tests/unit_tests/engine-key/openssl.cnf @@ -0,0 +1,12 @@ +HOME = . +openssl_conf = openssl_init + +[req] +[openssl_init] +engines = engines_section + +[engines_section] +testengine = testengine_section + +[testengine_section] +dynamic_path = $ENV::srcdir/.libs/libtestengine.so