From patchwork Tue Dec 14 05:59:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Selva Nair X-Patchwork-Id: 2168 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director7.mail.ord1d.rsapps.net ([172.27.255.52]) by backend41.mail.ord1d.rsapps.net with LMTP id CGycCOPNuGGuWAAAqwncew (envelope-from ) for ; Tue, 14 Dec 2021 12:01:23 -0500 Received: from proxy6.mail.iad3a.rsapps.net ([172.27.255.52]) by director7.mail.ord1d.rsapps.net with LMTP id OGPlKePNuGHAewAAovjBpQ (envelope-from ) for ; Tue, 14 Dec 2021 12:01:23 -0500 Received: from smtp36.gate.iad3a ([172.27.255.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy6.mail.iad3a.rsapps.net with LMTPS id 4IvOJOPNuGHWQQAA8udqhg (envelope-from ) for ; Tue, 14 Dec 2021 12:01:23 -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.105.38.7] Authentication-Results: smtp36.gate.iad3a.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; 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=gmail.com; dmarc=fail (p=none; dis=none) header.from=gmail.com X-Suspicious-Flag: YES X-Classification-ID: 76e50b6c-5cff-11ec-9608-525400575b2b-1-1 Received: from [216.105.38.7] ([216.105.38.7:33782] helo=lists.sourceforge.net) by smtp36.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 66/3F-25284-2EDC8B16; Tue, 14 Dec 2021 12:01:23 -0500 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.94.2) (envelope-from ) id 1mxB9p-00036j-6Y; Tue, 14 Dec 2021 17:00:06 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1mxB9i-00035O-9d for openvpn-devel@lists.sourceforge.net; Tue, 14 Dec 2021 16:59:59 +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:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: 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=xfkjR9LMwGPnUYG+RLbKSPc/cVs4vXg4MKiz6l75bgg=; b=fANrsf0O8xtTgkRn+/WpUcUoDG LB9H+aTzPbIRPEawEVYScqhrMe9RTlM3hWtqqByv9+xVaqKp87r9Ki0fFDOncsg39iN0bZFhbeTZX kU8bKcISO7nxJHxq8vajNKRztszwv9xXSxU+k1rr+TVKCkKHlctRmnG/VmViyB2i4z5I=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: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=xfkjR9LMwGPnUYG+RLbKSPc/cVs4vXg4MKiz6l75bgg=; b=e8L1rnrCqmlnjscK2yZBcUdBMB OccrSwAagnvQwOW/0SycqrpiuGDSXbUx8t/qxxXjWqfIU42AHqdw4E/Cv6K4L+u3zZmThrCZCi1hr ijKNRR6P/Gp2TAJI032V9LHEmItq1IinQijbB1ViguU45doirimC6scm2jYSXM1n/Wn4=; Received: from mail-io1-f43.google.com ([209.85.166.43]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.3) id 1mxB9i-00FKX3-Hi for openvpn-devel@lists.sourceforge.net; Tue, 14 Dec 2021 16:59:59 +0000 Received: by mail-io1-f43.google.com with SMTP id b187so25286451iof.11 for ; Tue, 14 Dec 2021 08:59:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xfkjR9LMwGPnUYG+RLbKSPc/cVs4vXg4MKiz6l75bgg=; b=dqNqgnvfUwCpPUCikErT98rxcLJTzaIO78BBaq3Db1UQIC7ovuT8Vgm9rPeuFO1ncH 7SMqZ8Jcco1GviRTlJ1tJ70+GmY6JQCuCRxtwvj5upn6GM89+1vOd2MprGm+03OcjjIs OOSXxLOwReWskqqVlrGh7Cn3tE8vfFYX31RcYAxgbk3m8Wh8//69f6iuwznlyF3P0w2Q q4E4r3Ld7TGNfUkxWFHoK1Fk8qkq7zscbWRcZtTLUTbYEOvj5D60c0iputa8Ddj2rnXc FNEKmCd/XRMlIKKHwI5RwHlZB9zV17RjUUtoBOOm34wS2sRLlSkyJOYbFn/butyIpEZe Aoow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xfkjR9LMwGPnUYG+RLbKSPc/cVs4vXg4MKiz6l75bgg=; b=X7XwhkJrGhCwUppI/hgXMl6vmUC02ADbCIwcXzx0RWqFMwcC5aiS0NtYTlHAxPbRpl RlnT/OHsvhxo+t38kfwGQy9L8F7jVV+/JD5ilMiwYkoPLay6FaUBHqaitG16KPQ1Nb9A /Csj2Qdte1WRW6Ta1s4QFHRiGVFepQIkcHecjVsETwxXE+eavf2RKYOIR5B5dL+Bn8qq 6hJroneg6BQ5nbE3tXoTq+43Iz0Ik3iZlb5MjRh6BHqv2Iktm4QKUA3/VutTNC+UH8b3 e2ewOWFRYtfWH13K1j3r0t6cKoIZuEG5B3+CCPNlAe4euY4DwW+hMSbr7QvOwpeuG/LK CKqQ== X-Gm-Message-State: AOAM531FX7OkleZsKGC0QQkGDBMP8CTGUKaU4A7hMba5xJww22f037Cm hCYwFlDYM0Hshp6uoMyNfKJc1bX5LYs= X-Google-Smtp-Source: ABdhPJyqBAiw2jPTaw88AXL4AFdOMio7/fKxsvh7effJuoVYuhNh9/PMSBgpz/0MTr9QXNf0pGkKlQ== X-Received: by 2002:a05:6638:2608:: with SMTP id m8mr3530367jat.57.1639501192671; Tue, 14 Dec 2021 08:59:52 -0800 (PST) Received: from uranus.home.sansel.ca (bras-vprn-tnhlon4053w-lp130-02-70-51-223-8.dsl.bell.ca. [70.51.223.8]) by smtp.gmail.com with ESMTPSA id e9sm178778ilm.44.2021.12.14.08.59.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Dec 2021 08:59:52 -0800 (PST) From: selva.nair@gmail.com To: openvpn-devel@lists.sourceforge.net Date: Tue, 14 Dec 2021 11:59:14 -0500 Message-Id: <20211214165928.30676-5-selva.nair@gmail.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20211214165928.30676-1-selva.nair@gmail.com> References: <20211214165928.30676-1-selva.nair@gmail.com> MIME-Version: 1.0 X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Selva Nair Our key object retains info about the external key as an opaque handle to the backend. We also need the public key as an EVP_PKEY *. For native keys we use OpenSSL API to import data into the key. The 'handle' representing the private key in that case is the OpenSSL EVP_PKEY object itself. Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [selva.nair[at]gmail.com] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.166.43 listed in wl.mailspike.net] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.166.43 listed in list.dnswl.org] -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -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: 1mxB9i-00FKX3-Hi Subject: [Openvpn-devel] [PATCH v3 04/18] Implement import of custom external 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 From: Selva Nair Our key object retains info about the external key as an opaque handle to the backend. We also need the public key as an EVP_PKEY *. For native keys we use OpenSSL API to import data into the key. The 'handle' representing the private key in that case is the OpenSSL EVP_PKEY object itself. For importing custom keys, we define custom parameters describing the key using OSSL_PARAM structure. We define 4 required and 1 optional parameters for loading the key: Required params of type OSSL_PARAM: {.key="xkey-origin", .data_type = OSSL_PARAM_UTF8_STRING .data = "foobar", .data_size = 0 } Note: data_size = 0 refer to NUL terminated string in OpenSSL. This parameter is only used to identify that the key as non-native with an opaque handle. We really do not check the content of the string. Should not be NULL. {.key="handle", .data_type = OSSL_PARAM_OCTET_PTR, .data = &handle, .data_size = sizeof(handle)} {.key="pubkey", .data_type = OSSL_PARAM_OCTET_STRING, .data = &pubkey, .data_size = sizeof(pubkey)} {.key="sign_op", .data_type = OSSL_PARAM_OCTET_PTR, .data = &sign_op_ptr, .data_size = sizeof(sign_op_ptr)} Optional param: {.key="free_op", .data_type = OSSL_PARAM_OCTET_PTR, .data = &free_op_ptr, .data_size = sizeof(free_op_ptr)} The 'handle' is opaque to us and is retained. The caller should not free it. We will free it when no longer required by calling 'free_op()', if provided. The 'handle' should not be NULL as that indicates missing private key. The 'pubkey' must be an 'EVP_PKEY *' variable, and is duplicated by us. The caller may free it after return from import. The 'sign_op' and 'free_op' function pointers should be of type 'XKEY_EXTERNAL_SIGN_fn' and 'XKEY_PRIVKEY_FREE_fn' defined in xkey_common.h For example, for management-external-key, we really do not need any 'handle'. Pass anything that will live long and won't dereference to NULL. We do not use it for any other purpose. Pointer to a const string could be a choice. In this case, free_op = NULL is the safest choice. For a usage of keymgmt_import(), see the helper function implemented using it to load the management key in the next commit. v2 changes: "origin" --> "xkey-origin" This was 5/9 in v1 Signed-off-by: Selva Nair Acked-By: Arne Schwabe --- src/openvpn/xkey_provider.c | 135 +++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/src/openvpn/xkey_provider.c b/src/openvpn/xkey_provider.c index 09138ae8..c2d560c5 100644 --- a/src/openvpn/xkey_provider.c +++ b/src/openvpn/xkey_provider.c @@ -78,6 +78,13 @@ typedef enum * * We also keep the public key in the form of a native OpenSSL EVP_PKEY. * This allows us to do all public ops by calling ops in the default provider. + * Both these are references retained by us and freed when the key is + * destroyed. As the pubkey is native, we free it using EVP_PKEY_free(). + * To free the handle we call the backend if a free function + * has been set for that key. It could be set when the key is + * created/imported. + * For native keys, there is no need to free the handle as its either + * NULL of the same as the pubkey which we always free. */ typedef struct { @@ -133,6 +140,9 @@ static OSSL_FUNC_keymgmt_set_params_fn keymgmt_set_params; static OSSL_FUNC_keymgmt_query_operation_name_fn rsa_keymgmt_name; static OSSL_FUNC_keymgmt_query_operation_name_fn ec_keymgmt_name; +static int +keymgmt_import_helper(XKEY_KEYDATA *key, const OSSL_PARAM params[]); + static XKEY_KEYDATA * keydata_new() { @@ -156,6 +166,11 @@ keydata_free(XKEY_KEYDATA *key) { return; } + if (key->free && key->handle) + { + key->free(key->handle); + key->handle = NULL; + } if (key->pubkey) { EVP_PKEY_free(key->pubkey); @@ -195,7 +210,27 @@ keymgmt_load(const void *reference, size_t reference_sz) * appropriate for the key. We just use it to create a native * EVP_PKEY from params and assign to keydata->handle. * - * Import of external keys -- to be implemented + * For non-native keys the params[] array should include a custom + * value with name "xkey-origin". + * + * Other required parameters in the params array are: + * + * pubkey - pointer to native public key as a OCTET_STRING + * the public key is duplicated on receipt + * handle - reference to opaque handle to private key -- if not required + * pass a dummy value that is not zero. type = OCTET_PTR + * The reference is retained -- caller must _not_ free it. + * sign_op - function pointer for sign operation. type = OCTET_PTR + * Must be a reference to XKEY_EXTERNAL_SIGN_fn + * xkey-origin - A custom string to indicate the external key origin. UTF8_STRING + * The value doesn't really matter, but must be present. + * + * Optional params + * free_op - Called as free(handle) when the key is deleted. If the + * handle should not be freed, do not include. type = OCTET_PTR + * Must be a reference to XKEY_PRIVKEY_FREE_fn + * + * See xkey_load_management_key for an example use. */ static int keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[], const char *name) @@ -212,6 +247,17 @@ keymgmt_import(void *keydata, int selection, const OSSL_PARAM params[], const ch return 0; } + /* if params contain a custom origin, call our helper to import custom keys */ + const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, "xkey-origin"); + if (p && p->data_type == OSSL_PARAM_UTF8_STRING) + { + key->origin = EXTERNAL_KEY; + xkey_dmsg(D_LOW, "importing external key"); + return keymgmt_import_helper(key, params); + } + + xkey_dmsg(D_LOW, "importing native key"); + /* create a native public key and assign it to key->pubkey */ EVP_PKEY *pkey = NULL; int selection_pub = selection & ~OSSL_KEYMGMT_SELECT_PRIVATE_KEY; @@ -370,10 +416,95 @@ keymgmt_get_params(void *keydata, OSSL_PARAM *params) return EVP_PKEY_get_params(key->pubkey, params); } +/* Helper used by keymgmt_import and keymgmt_set_params + * for our keys. Not to be used for OpenSSL native keys. + */ +static int +keymgmt_import_helper(XKEY_KEYDATA *key, const OSSL_PARAM *params) +{ + xkey_dmsg(D_LOW, "entry"); + + const OSSL_PARAM *p; + EVP_PKEY *pkey = NULL; + + ASSERT(key); + /* calling this with native keys is a coding error */ + ASSERT(key->origin != OPENSSL_NATIVE); + + if (params == NULL) + { + return 1; /* not an error */ + } + + /* our keys are immutable, we do not allow resetting parameters */ + if (key->pubkey) + { + return 0; + } + + /* only check params we understand and ignore the rest */ + + p = OSSL_PARAM_locate_const(params, "pubkey"); /*setting pubkey on our keydata */ + if (p && p->data_type == OSSL_PARAM_OCTET_STRING + && p->data_size == sizeof(pkey)) + { + pkey = *(EVP_PKEY **)p->data; + ASSERT(pkey); + + int id = EVP_PKEY_get_id(pkey); + if (id != EVP_PKEY_RSA && id != EVP_PKEY_EC) + { + msg(M_WARN, "Error: xkey keymgmt_import: unknown key type (%d)", id); + return 0; + } + + key->pubkey = EVP_PKEY_dup(pkey); + if (key->pubkey == NULL) + { + msg(M_NONFATAL, "Error: xkey keymgmt_import: duplicating pubkey failed."); + return 0; + } + } + + p = OSSL_PARAM_locate_const(params, "handle"); /*setting privkey */ + if (p && p->data_type == OSSL_PARAM_OCTET_PTR + && p->data_size == sizeof(key->handle)) + { + key->handle = *(void **)p->data; + /* caller should keep the reference alive until we call free */ + ASSERT(key->handle); /* fix your params array */ + } + + p = OSSL_PARAM_locate_const(params, "sign_op"); /*setting sign_op */ + if (p && p->data_type == OSSL_PARAM_OCTET_PTR + && p->data_size == sizeof(key->sign)) + { + key->sign = *(void **)p->data; + ASSERT(key->sign); /* fix your params array */ + } + + /* optional parameters */ + p = OSSL_PARAM_locate_const(params, "free_op"); /*setting free_op */ + if (p && p->data_type == OSSL_PARAM_OCTET_PTR + && p->data_size == sizeof(key->free)) + { + key->free = *(void **)p->data; + } + xkey_dmsg(D_LOW, "imported external %s key", EVP_PKEY_get0_type_name(key->pubkey)); + + return 1; +} + /** + * Set params on a key. + * * If the key is an encapsulated native key, we just call * EVP_PKEY_set_params in the default context. Only those params * supported by the default provider would work in this case. + * + * We treat our key object as immutable, so this works only with an + * empty key. Supported params for external keys are the + * same as those listed in the description of keymgmt_import. */ static int keymgmt_set_params(void *keydata, const OSSL_PARAM *params) @@ -385,7 +516,7 @@ keymgmt_set_params(void *keydata, const OSSL_PARAM *params) if (key->origin != OPENSSL_NATIVE) { - return 0; /* to be implemented */ + return keymgmt_import_helper(key, params); } else if (key->handle == NULL) /* once handle is set our key is immutable */ {