From patchwork Tue Dec 14 05:59:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Selva Nair X-Patchwork-Id: 2182 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director11.mail.ord1d.rsapps.net ([172.30.191.6]) by backend41.mail.ord1d.rsapps.net with LMTP id sA7KF+rNuGHPWAAAqwncew (envelope-from ) for ; Tue, 14 Dec 2021 12:01:30 -0500 Received: from proxy11.mail.ord1d.rsapps.net ([172.30.191.6]) by director11.mail.ord1d.rsapps.net with LMTP id mMkeOerNuGGmAQAAvGGmqA (envelope-from ) for ; Tue, 14 Dec 2021 12:01:30 -0500 Received: from smtp30.gate.ord1d ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy11.mail.ord1d.rsapps.net with LMTPS id uLG4N9fNuGGLLwAAgKDEHA (envelope-from ) for ; Tue, 14 Dec 2021 12:01:11 -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: smtp30.gate.ord1d.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: 7aa2f2fa-5cff-11ec-9dbf-5254001e8e38-1-1 Received: from [216.105.38.7] ([216.105.38.7:38934] helo=lists.sourceforge.net) by smtp30.gate.ord1d.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id F1/EF-02332-8EDC8B16; Tue, 14 Dec 2021 12:01:29 -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 1mxB9o-00036e-Ry; Tue, 14 Dec 2021 17:00:05 +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 1mxB9h-00035H-I5 for openvpn-devel@lists.sourceforge.net; Tue, 14 Dec 2021 16:59:58 +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=0gRbtL07i7FO5zZUkCeYJKPe4hgBRnOY7FpKPKose3c=; b=aYIDw/56zPEzNsaCskYwipd4+Y HhSUz+lG5qlxocRxZd9B8jauNGlLS1FYz0+O4+cQmNDNtqyn79GH61cq4tgaKP38ycyF9x8/6U31o Yhm54TntIqlw/ne0ncnuuwJQi57Vn8HX/wBnbVQ52fRwba+qfGu4ul6USi79OfqPB8X0=; 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=0gRbtL07i7FO5zZUkCeYJKPe4hgBRnOY7FpKPKose3c=; b=F+vWbCD5z30paticaIYRo5BmVQ YJuhZ+hKPyeTnF3dJ8DxV9DY4cfJKYsc3ySVKl34J4Q/3mdy7wsMVi6figDDTIKepQX48ND25y6zL RpwmxylIDX7F9wyD2XzPEkxZCJ1ZAtdZN4sxTQoGDKURoUcrDEVpVIu1gGAoWMMfsd6Q=; Received: from mail-il1-f179.google.com ([209.85.166.179]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.92.3) id 1mxB9h-00FKX2-Dk for openvpn-devel@lists.sourceforge.net; Tue, 14 Dec 2021 16:59:58 +0000 Received: by mail-il1-f179.google.com with SMTP id d17so18879ils.8 for ; Tue, 14 Dec 2021 08:59:57 -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=0gRbtL07i7FO5zZUkCeYJKPe4hgBRnOY7FpKPKose3c=; b=dhwr+nGAGlSjC1sEtwVVA4n4i8wto+QL9iHCDo8nRz0Z01AIPkHK6NdB9WvbWfDOkn p3GpDp2HJT8HJ43rBDIT825xCyafQ4008n2+FYM0aBcpLWiw4zRAwPy+y4IcYiAuSmGs zxDumyvVx2PoT+CLFrykVZ2V+swdNuIwZ/gdeTHvjbPvGz6GUpU+H7YpkOmVhQ5La1XB qd5R0c5/pQoAGpj4Znt+/2y0ME08NxtbZ4Q3ks3W51Rinr7/GQz7aZrZkCGLrGAycah8 TvdBCU/IDA4sMNpQ9/4UxlevRgRSOHwZA0U2ep719vRd40bwO+U1xFLzBeVsU0cbfHS/ iUIw== 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=0gRbtL07i7FO5zZUkCeYJKPe4hgBRnOY7FpKPKose3c=; b=d1X22fcvt9JGDSoDDaiB+GeevZ1+neWCK5zr8VApWauNVgyD4z/8CG82zy2KaL+1Gm XCWCclp9Hr8j2v0cYB21JB+k5Gku6ePvOGzTs8G3br76wZTS1KIY/MX6qf3cp9T9vDwv zbVY0GMS8Z+HHY2R6tS7HVCbxua2czip2593uxK6VXspC5tB2UlYBo2nkKyz2I4ZgvHU vPBPm1vNNl2gChtBFvUw3XhNUevPBleuC880iJv8PGWsm04WxX5jesXRDKx+5k1im1Oq IJC+l75b2/nLqh3LxM4R0K+W477FIZGIzeVeIj+JiQ4L2LHfs9h1FwFR1kHY1f+1JnEb N73w== X-Gm-Message-State: AOAM530IXQQov7KlgWEa+znglgCviSht3XMwPdkWaUWhxJKWI/pSPLrQ QB77TAoefZhlk74h4H2kSAdV8/ZCFTs= X-Google-Smtp-Source: ABdhPJx4A90pE5lAOqbu1doXjKRFil4zRLi9SUBu6pS0eKbWwUuqDQsAqi+zKCBGGFSzKzL63my5Rw== X-Received: by 2002:a05:6e02:214a:: with SMTP id d10mr4436216ilv.134.1639501191330; Tue, 14 Dec 2021 08:59:51 -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.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Dec 2021 08:59:51 -0800 (PST) From: selva.nair@gmail.com To: openvpn-devel@lists.sourceforge.net Date: Tue, 14 Dec 2021 11:59:13 -0500 Message-Id: <20211214165928.30676-4-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 - Basic frame work for announcing support for signature operations - DigestSign and Sign functions for native keys are also implemented. Though strictly not needed, these functions for native keys sets up the framework for signature operations. They also help loading [...] 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.179 listed in wl.mailspike.net] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.166.179 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: 1mxB9h-00FKX2-Dk Subject: [Openvpn-devel] [PATCH v3 03/18] Implement SIGNATURE operations in xkey provider 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 - Basic frame work for announcing support for signature operations - DigestSign and Sign functions for native keys are also implemented. Though strictly not needed, these functions for native keys sets up the framework for signature operations. They also help loading an exportable key from a file through the provider for testing. Subsequent commits will add support for signing with external keys. v2 changes: - Remove verify operations which are no longer required with proposed changes in OpenSSL 3.0.1 that we target. - Undigested message is passed to the backend sign operation when possible. This would allow more flexibility as some backends prefer to do the hash operation internally. This was 4/9 in v1 Signed-off-by: Selva Nair Acked-By: Arne Schwabe --- src/openvpn/xkey_common.h | 43 +++ src/openvpn/xkey_provider.c | 530 +++++++++++++++++++++++++++++++++++- 2 files changed, 566 insertions(+), 7 deletions(-) diff --git a/src/openvpn/xkey_common.h b/src/openvpn/xkey_common.h index a3bc3f2a..db58d077 100644 --- a/src/openvpn/xkey_common.h +++ b/src/openvpn/xkey_common.h @@ -40,6 +40,49 @@ OSSL_provider_init_fn xkey_provider_init; #define XKEY_PROV_PROPS "provider=ovpn.xkey" +/** + * Stuct to encapsulate signature algorithm parameters to pass + * to sign operation. + */ +typedef struct { + const char *padmode; /**< "pkcs1", "pss" or "none" */ + const char *mdname; /**< "SHA256" or "SHA2-256" etc. */ + const char *saltlen; /**< "digest", "auto" or "max" */ + const char *keytype; /**< "EC" or "RSA" */ + const char *op; /**< "Sign" or "DigestSign" */ +} XKEY_SIGALG; + +/** + * Callback for sign operation -- must be implemented for each backend and + * is used in xkey_signature_sign(), or set when loading the key. + * (custom key loading not yet implemented). + * + * @param handle opaque key handle provided by the backend -- could be null + * or unused for management interface. + * @param sig On return caller should fill this with the signature + * @param siglen On entry *siglen has max size of sig and on return must be + * set to the actual size of the signature + * @param tbs buffer to sign + * @param tbslen size of data in tbs buffer + * @sigalg contains the signature algorithm parameters + * + * @returns 1 on success, 0 on error. + * + * The data in tbs is just the digest with no DigestInfo header added. This is + * unlike the deprecated RSA_sign callback which provides encoded digest. + * For RSA_PKCS1 signatures, the external signing function must encode the digest + * before signing. The digest algorithm used is passed in the sigalg structure. + */ +typedef int (XKEY_EXTERNAL_SIGN_fn)(void *handle, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen, + XKEY_SIGALG sigalg); +/** + * Signature of private key free function callback used + * to free the opaque private key handle obtained from the + * backend. Not required for management-external-key. + */ +typedef void (XKEY_PRIVKEY_FREE_fn)(void *handle); + #endif /* HAVE_XKEY_PROVIDER */ #endif /* XKEY_COMMON_H_ */ diff --git a/src/openvpn/xkey_provider.c b/src/openvpn/xkey_provider.c index a083ec2d..09138ae8 100644 --- a/src/openvpn/xkey_provider.c +++ b/src/openvpn/xkey_provider.c @@ -81,18 +81,40 @@ typedef enum */ typedef struct { - /* opaque handle dependent on KEY_ORIGIN -- could be NULL */ + /** opaque handle dependent on KEY_ORIGIN -- could be NULL */ void *handle; - /* associated public key as an openvpn native key */ + /** associated public key as an openvpn native key */ EVP_PKEY *pubkey; - /* origin of key -- native or external */ + /** origin of key -- native or external */ XKEY_ORIGIN origin; + /** sign function in backend to call */ + XKEY_EXTERNAL_SIGN_fn *sign; + /** keydata handle free function of backend */ + XKEY_PRIVKEY_FREE_fn *free; XKEY_PROVIDER_CTX *prov; - int refcount; /* reference count */ + int refcount; /**< reference count */ } XKEY_KEYDATA; -#define KEYTYPE(key) ((key)->pubkey ? EVP_PKEY_get_id((key)->pubkey) : 0) -#define KEYSIZE(key) ((key)->pubkey ? EVP_PKEY_get_size((key)->pubkey) : 0) +static int +KEYTYPE(const XKEY_KEYDATA *key) +{ + return key->pubkey ? EVP_PKEY_get_id(key->pubkey) : 0; +} + +static int +KEYSIZE(const XKEY_KEYDATA *key) +{ + return key->pubkey ? EVP_PKEY_get_size(key->pubkey) : 0; +} + +/** + * Helper sign function for native keys + * Implemented using OpenSSL calls. + */ +int +xkey_native_sign(XKEY_KEYDATA *key, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen, XKEY_SIGALG sigalg); + /* keymgmt provider */ @@ -390,6 +412,19 @@ ec_keymgmt_name(int id) { xkey_dmsg(D_LOW, "entry"); + if (id == OSSL_OP_SIGNATURE) + { + return "ECDSA"; + } + /* though we do not implement keyexch we could be queried for + * keyexch mechanism supported by EC keys + */ + else if (id == OSSL_OP_KEYEXCH) + { + return "ECDH"; + } + + msg(D_LOW, "xkey ec_keymgmt_name called with op_id != SIGNATURE or KEYEXCH id=%d", id); return "EC"; } @@ -432,6 +467,487 @@ const OSSL_ALGORITHM keymgmts[] = { {NULL, NULL, NULL, NULL} }; + +/* signature provider */ + +/* signature provider callbacks we provide */ +static OSSL_FUNC_signature_newctx_fn signature_newctx; +static OSSL_FUNC_signature_freectx_fn signature_freectx; +static OSSL_FUNC_signature_sign_init_fn signature_sign_init; +static OSSL_FUNC_signature_sign_fn signature_sign; +static OSSL_FUNC_signature_digest_verify_init_fn signature_digest_verify_init; +static OSSL_FUNC_signature_digest_verify_fn signature_digest_verify; +static OSSL_FUNC_signature_digest_sign_init_fn signature_digest_sign_init; +static OSSL_FUNC_signature_digest_sign_fn signature_digest_sign; +static OSSL_FUNC_signature_set_ctx_params_fn signature_set_ctx_params; +static OSSL_FUNC_signature_settable_ctx_params_fn signature_settable_ctx_params; +static OSSL_FUNC_signature_get_ctx_params_fn signature_get_ctx_params; +static OSSL_FUNC_signature_gettable_ctx_params_fn signature_gettable_ctx_params; + +typedef struct +{ + XKEY_PROVIDER_CTX *prov; + XKEY_KEYDATA *keydata; + XKEY_SIGALG sigalg; +} XKEY_SIGNATURE_CTX; + +static const XKEY_SIGALG default_sigalg = { .mdname="MD5-SHA1", .saltlen="digest", + .padmode="pkcs1", .keytype = "RSA"}; + +const struct { + int nid; + const char *name; +} digest_names[] = {{NID_md5_sha1, "MD5-SHA1"}, {NID_sha1, "SHA1"}, + {NID_sha224, "SHA224",}, {NID_sha256, "SHA256"}, {NID_sha384, "SHA384"}, + {NID_sha512, "SHA512"}, {0, NULL}}; +/* Use of NIDs as opposed to EVP_MD_fetch is okay here + * as these are only used for converting names passed in + * by OpenSSL to const strings. + */ + +static struct { + int id; + const char *name; +} padmode_names[] = {{RSA_PKCS1_PADDING, "pkcs1"}, + {RSA_PKCS1_PSS_PADDING, "pss"}, + {RSA_NO_PADDING, "none"}, + {0, NULL}}; + +static const char *saltlen_names[] = {"digest", "max", "auto", NULL}; + +/* Return a string literal for digest name - normalizes + * alternate names like SHA2-256 to SHA256 etc. + */ +static const char * +xkey_mdname(const char *name) +{ + int i = 0; + + int nid = EVP_MD_get_type(EVP_get_digestbyname(name)); + + while (digest_names[i].name && nid != digest_names[i].nid) + { + i++; + } + return digest_names[i].name ? digest_names[i].name : "MD5-SHA1"; +} + +static void * +signature_newctx(void *provctx, const char *propq) +{ + xkey_dmsg(D_LOW, "entry"); + + (void) propq; /* unused */ + + XKEY_SIGNATURE_CTX *sctx = OPENSSL_zalloc(sizeof(*sctx)); + if (!sctx) + { + msg(M_NONFATAL, "xkey_signature_newctx: out of memory"); + return NULL; + } + + sctx->prov = provctx; + sctx->sigalg = default_sigalg; + + return sctx; +} + +static void +signature_freectx(void *ctx) +{ + xkey_dmsg(D_LOW, "entry"); + + XKEY_SIGNATURE_CTX *sctx = ctx; + + keydata_free(sctx->keydata); + + OPENSSL_free(sctx); +} + +static const OSSL_PARAM * +signature_settable_ctx_params(void *ctx, void *provctx) +{ + xkey_dmsg(D_LOW, "entry"); + + static OSSL_PARAM settable[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), + OSSL_PARAM_END + }; + + return settable; +} + +static int +signature_set_ctx_params(void *ctx, const OSSL_PARAM params[]) +{ + xkey_dmsg(D_LOW, "entry"); + + XKEY_SIGNATURE_CTX *sctx = ctx; + const OSSL_PARAM *p; + + if (params == NULL) + { + return 1; /* not an error */ + } + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE); + if (p && p->data_type == OSSL_PARAM_UTF8_STRING) + { + sctx->sigalg.padmode = NULL; + for (int i = 0; padmode_names[i].id != 0; i++) + { + if (!strcmp(p->data, padmode_names[i].name)) + { + sctx->sigalg.padmode = padmode_names[i].name; + break; + } + } + if (sctx->sigalg.padmode == NULL) + { + msg(M_WARN, "xkey signature_ctx: padmode <%s>, treating as ", + (char *)p->data); + sctx->sigalg.padmode = "none"; + } + xkey_dmsg(D_LOW, "setting padmode as %s", sctx->sigalg.padmode); + } + else if (p && p->data_type == OSSL_PARAM_INTEGER) + { + sctx->sigalg.padmode = NULL; + int padmode = 0; + if (OSSL_PARAM_get_int(p, &padmode)) + { + for (int i = 0; padmode_names[i].id != 0; i++) + { + if (padmode == padmode_names[i].id) + { + sctx->sigalg.padmode = padmode_names[i].name; + break; + } + } + } + if (padmode == 0 || sctx->sigalg.padmode == NULL) + { + msg(M_WARN, "xkey signature_ctx: padmode <%d>, treating as ", padmode); + sctx->sigalg.padmode = "none"; + } + xkey_dmsg(D_LOW, "setting padmode <%s>", sctx->sigalg.padmode); + } + else if (p) + { + msg(M_WARN, "xkey_signature_params: unknown padmode ignored"); + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p && p->data_type == OSSL_PARAM_UTF8_STRING) + { + sctx->sigalg.mdname = xkey_mdname(p->data); + xkey_dmsg(D_LOW, "setting hashalg as %s", sctx->sigalg.mdname); + } + else if (p) + { + msg(M_WARN, "xkey_signature_params: unknown digest type ignored"); + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN); + if (p && p->data_type == OSSL_PARAM_UTF8_STRING) + { + sctx->sigalg.saltlen = NULL; + for (int i = 0; saltlen_names[i] != NULL; i++) + { + if (!strcmp(p->data, saltlen_names[i])) + { + sctx->sigalg.saltlen = saltlen_names[i]; + break; + } + } + if (sctx->sigalg.saltlen == NULL) + { + msg(M_WARN, "xkey_signature_params: unknown saltlen <%s>", + (char *)p->data); + sctx->sigalg.saltlen = "digest"; /* most common */ + } + xkey_dmsg(D_LOW, "setting saltlen to %s", sctx->sigalg.saltlen); + } + else if (p) + { + msg(M_WARN, "xkey_signature_params: unknown saltlen ignored"); + } + + return 1; +} + +static const OSSL_PARAM * +signature_gettable_ctx_params(void *ctx, void *provctx) +{ + xkey_dmsg(D_LOW,"entry"); + + static OSSL_PARAM gettable[] = { OSSL_PARAM_END }; /* Empty list */ + + return gettable; +} + +static int +signature_get_ctx_params(void *ctx, OSSL_PARAM params[]) +{ + xkey_dmsg(D_LOW, "not implemented"); + return 0; +} + +static int +signature_sign_init(void *ctx, void *provkey, const OSSL_PARAM params[]) +{ + xkey_dmsg(D_LOW, "entry"); + + XKEY_SIGNATURE_CTX *sctx = ctx; + + if (sctx->keydata) + { + keydata_free(sctx->keydata); + } + sctx->keydata = provkey; + sctx->keydata->refcount++; /* we are keeping a copy */ + sctx->sigalg.keytype = KEYTYPE(sctx->keydata) == EVP_PKEY_RSA ? "RSA" : "EC"; + + signature_set_ctx_params(sctx, params); + + return 1; +} + +/* Sign digest or message using sign function */ +static int +xkey_sign_dispatch(XKEY_SIGNATURE_CTX *sctx, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen) +{ + XKEY_EXTERNAL_SIGN_fn *sign = sctx->keydata->sign; + int ret = 0; + + if (sctx->keydata->origin == OPENSSL_NATIVE) + { + ret = xkey_native_sign(sctx->keydata, sig, siglen, tbs, tbslen, sctx->sigalg); + } + else if (sign) + { + ret = sign(sctx->keydata->handle, sig, siglen, tbs, tbslen, sctx->sigalg); + xkey_dmsg(D_LOW, "xkey_provider: external sign op returned ret = %d siglen = %d", ret, (int) *siglen); + } + else + { + msg(M_NONFATAL, "xkey_provider: Internal error: No sign callback for external key."); + } + + return ret; +} + +static int +signature_sign(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + xkey_dmsg(D_LOW, "entry with siglen = %zu\n", *siglen); + + XKEY_SIGNATURE_CTX *sctx = ctx; + ASSERT(sctx); + ASSERT(sctx->keydata); + + if (!sig) + { + *siglen = KEYSIZE(sctx->keydata); + return 1; + } + + sctx->sigalg.op = "Sign"; + return xkey_sign_dispatch(sctx, sig, siglen, tbs, tbslen); +} + +static int +signature_digest_verify_init(void *ctx, const char *mdname, void *provkey, + const OSSL_PARAM params[]) +{ + xkey_dmsg(D_LOW, "mdname <%s>", mdname); + + msg(M_WARN, "xkey_provider: DigestVerifyInit is not implemented"); + return 0; +} + +/* We do not expect to be called for DigestVerify() but still + * return an empty function for it in the sign dispatch array + * for debugging purposes. + */ +static int +signature_digest_verify(void *ctx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + xkey_dmsg(D_LOW, "entry"); + + msg(M_WARN, "xkey_provider: DigestVerify is not implemented"); + return 0; +} + +static int +signature_digest_sign_init(void *ctx, const char *mdname, + void *provkey, const OSSL_PARAM params[]) +{ + xkey_dmsg(D_LOW, "mdname = <%s>", mdname); + + XKEY_SIGNATURE_CTX *sctx = ctx; + + ASSERT(sctx); + ASSERT(provkey); + ASSERT(sctx->prov); + + if (sctx->keydata) + { + keydata_free(sctx->keydata); + } + sctx->keydata = provkey; /* used by digest_sign */ + sctx->keydata->refcount++; + sctx->sigalg.keytype = KEYTYPE(sctx->keydata) == EVP_PKEY_RSA ? "RSA" : "EC"; + + signature_set_ctx_params(ctx, params); + if (mdname) + { + sctx->sigalg.mdname = xkey_mdname(mdname); /* get a string literal pointer */ + } + else + { + msg(M_WARN, "xkey digest_sign_init: mdname is NULL."); + } + return 1; +} + +static int +signature_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + xkey_dmsg(D_LOW, "entry"); + + XKEY_SIGNATURE_CTX *sctx = ctx; + + ASSERT(sctx); + ASSERT(sctx->keydata); + + if (!sig) /* set siglen and return */ + { + *siglen = KEYSIZE(sctx->keydata); + return 1; + } + + if (sctx->keydata->origin != OPENSSL_NATIVE) + { + /* pass the message itself to the backend */ + sctx->sigalg.op = "DigestSign"; + return xkey_sign_dispatch(ctx, sig, siglen, tbs, tbslen); + } + + /* create digest and pass on to signature_sign() */ + + const char *mdname = sctx->sigalg.mdname; + EVP_MD *md = EVP_MD_fetch(sctx->prov->libctx, mdname, NULL); + if (!md) + { + msg(M_WARN, "WARN: xkey digest_sign_init: MD_fetch failed for <%s>", mdname); + return 0; + } + + /* construct digest using OpenSSL */ + unsigned char buf[EVP_MAX_MD_SIZE]; + unsigned int sz; + if (EVP_Digest(tbs, tbslen, buf, &sz, md, NULL) != 1) + { + msg(M_WARN, "WARN: xkey digest_sign: EVP_Digest failed"); + EVP_MD_free(md); + return 0; + } + EVP_MD_free(md); + + return signature_sign(ctx, sig, siglen, sigsize, buf, sz); +} + +/* Sign digest using native sign function -- will only work for native keys + */ +int +xkey_native_sign(XKEY_KEYDATA *key, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen, XKEY_SIGALG sigalg) +{ + xkey_dmsg(D_LOW, "entry"); + + ASSERT(key); + + EVP_PKEY *pkey = key->handle; + int ret = 0; + + ASSERT(sig); + + if (!pkey) + { + msg(M_NONFATAL, "Error: xkey provider: signature request with empty private key"); + return 0; + } + + const char *saltlen = sigalg.saltlen; + const char *mdname = sigalg.mdname; + const char *padmode = sigalg.padmode; + + xkey_dmsg(D_LOW, "digest=<%s>, padmode=<%s>, saltlen=<%s>", mdname, padmode, saltlen); + + int i = 0; + OSSL_PARAM params[6]; + if (EVP_PKEY_get_id(pkey) == EVP_PKEY_RSA) + { + params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, (char *)mdname, 0); + params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, (char *)padmode, 0); + if (!strcmp(sigalg.padmode, "pss")) + { + params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, (char *) saltlen, 0); + /* same digest for mgf1 */ + params[i++] = OSSL_PARAM_construct_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, (char *) mdname, 0); + } + } + params[i++] = OSSL_PARAM_construct_end(); + + EVP_PKEY_CTX *ectx = EVP_PKEY_CTX_new_from_pkey(key->prov->libctx, pkey, NULL); + + if (!ectx) + { + msg(M_WARN, "WARN: xkey test_sign: call to EVP_PKEY_CTX_new...failed"); + return 0; + } + + if (EVP_PKEY_sign_init_ex(ectx, NULL) != 1) + { + msg(M_WARN, "WARN: xkey test_sign: call to EVP_PKEY_sign_init failed"); + return 0; + } + EVP_PKEY_CTX_set_params(ectx, params); + + ret = EVP_PKEY_sign(ectx, sig, siglen, tbs, tbslen); + EVP_PKEY_CTX_free(ectx); + + return ret; +} + +static const OSSL_DISPATCH signature_functions[] = { + {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void)) signature_newctx}, + {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void)) signature_freectx}, + {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void)) signature_sign_init}, + {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void)) signature_sign}, + {OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, (void (*)(void)) signature_digest_verify_init}, + {OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, (void (*)(void)) signature_digest_verify}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void)) signature_digest_sign_init}, + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN, (void (*)(void)) signature_digest_sign}, + {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void)) signature_set_ctx_params}, + {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void)) signature_settable_ctx_params}, + {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void)) signature_get_ctx_params}, + {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void)) signature_gettable_ctx_params}, + {0, NULL } +}; + +const OSSL_ALGORITHM signatures[] = { + {"RSA:rsaEncryption", props, signature_functions, "OpenVPN xkey RSA Signature"}, + {"ECDSA", props, signature_functions, "OpenVPN xkey ECDSA Signature"}, + {NULL, NULL, NULL, NULL} +}; + /* main provider interface */ /* provider callbacks we implement */ @@ -450,7 +966,7 @@ query_operation(void *provctx, int op, int *no_store) switch (op) { case OSSL_OP_SIGNATURE: - return NULL; + return signatures; case OSSL_OP_KEYMGMT: return keymgmts;