From patchwork Wed Mar 23 02:49:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: zhenwei pi X-Patchwork-Id: 553809 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C7860C433EF for ; Wed, 23 Mar 2022 02:53:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230312AbiCWCyd (ORCPT ); Tue, 22 Mar 2022 22:54:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54672 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231901AbiCWCyc (ORCPT ); Tue, 22 Mar 2022 22:54:32 -0400 Received: from mail-pj1-x102e.google.com (mail-pj1-x102e.google.com [IPv6:2607:f8b0:4864:20::102e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21D67B87A for ; Tue, 22 Mar 2022 19:53:03 -0700 (PDT) Received: by mail-pj1-x102e.google.com with SMTP id mm17-20020a17090b359100b001c6da62a559so5105279pjb.3 for ; Tue, 22 Mar 2022 19:53:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Sg3To/7UT7Td+uZYPu+oDeRZF15OaGdKfSNym1I4/hE=; b=4UFMN77XWGnYrRYUy3LKDWngeQjcECwfMkSuMWtxxC01Akzeu9rHwKC/nGRbsx3p+2 VCxF52uasYyYrHRkyOh+UL7ZleClsNHlJIG/BgTX+n29BknYqaJXgHYex7zkFcJEnxWM s9dy6tEJouexU56Y7ZW51UabbJhg1PQIHTEBlWZ6yB2YbPwFblRZPeN9zCxo6ABbHmWD J4dYAVyp/ryWLppvP0GCLaSmmX8MhocgX0iU3QNHiSKEwHw8j+2vVXS5nXaelIXbmubL sJLeCDJMldX4Af4DaoOeTzzuNfhczd498hcReSq2TmrFmzcMq1F6xIgMagR9Fjp2CQe+ PsGA== 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=Sg3To/7UT7Td+uZYPu+oDeRZF15OaGdKfSNym1I4/hE=; b=grT5cPV5rms86Hn0iaM9o0AflTmPOeoEFDC4gp5/VpCQsi6dognqi29+CqZoDW9XOV pmVkr8zvTaVKvD5DSeNW7R+tMmAn40H2qbKtrSQxqDiFxUnWj/ni0fOvDwvT2LgQenTX VopH87+gWGXSppGexrOaooLaXR9b9Dy+ZtMzZha+hjBqNY6fJlxJGeLIUE5K3S1jdGH0 SKfu7QNPC/GusxLUVaj69lbTWVtwIyJ/7VSkJqSIxMpNKi64XuzGzNhFR+z3xMv1jVuH 7uEZJ1oRc5biZ0RsYWfO2I+FKbhOCrYCscoUtOEexFlW+2c4Qzjoq5jYfuIq1UhAPak6 Vaaw== X-Gm-Message-State: AOAM533t0mXnNzjEHHV2LIWYensYLgSwi4HWc5pgoDVRbReUSGlnayI6 OpNbJ3e7I1HlAhJmmOO7a45Rtg== X-Google-Smtp-Source: ABdhPJzz4RA92uPgrSrtlvMjFp57uCew5sRe8hpZlNEi889wNBDUneICR+l2GiXixacITs4a6375sw== X-Received: by 2002:a17:902:7049:b0:151:e52e:ae42 with SMTP id h9-20020a170902704900b00151e52eae42mr22231853plt.118.1648003982647; Tue, 22 Mar 2022 19:53:02 -0700 (PDT) Received: from always-x1.www.tendawifi.com ([139.177.225.224]) by smtp.gmail.com with ESMTPSA id t2-20020a63a602000000b0038062a0bc6fsm18104869pge.67.2022.03.22.19.52.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Mar 2022 19:53:01 -0700 (PDT) From: zhenwei pi To: arei.gonglei@huawei.com, mst@redhat.com Cc: jasowang@redhat.com, virtualization@lists.linux-foundation.org, qemu-devel@nongnu.org, linux-crypto@vger.kernel.org, herbert@gondor.apana.org.au, Lei He , zhenwei pi Subject: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi Date: Wed, 23 Mar 2022 10:49:08 +0800 Message-Id: <20220323024912.249789-3-pizhenwei@bytedance.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220323024912.249789-1-pizhenwei@bytedance.com> References: <20220323024912.249789-1-pizhenwei@bytedance.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org From: Lei He Introduce akcipher types, also include RSA & ECDSA related types. Signed-off-by: Lei He Signed-off-by: zhenwei pi --- qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/qapi/crypto.json b/qapi/crypto.json index 1ec54c15ca..d44c38e3b1 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -540,3 +540,89 @@ 'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] }, '*sanity-check': 'bool', '*passwordid': 'str' } } +## +# @QCryptoAkcipherAlgorithm: +# +# The supported algorithms for asymmetric encryption ciphers +# +# @rsa: RSA algorithm +# @ecdsa: ECDSA algorithm +# +# Since: 7.0 +## +{ 'enum': 'QCryptoAkcipherAlgorithm', + 'prefix': 'QCRYPTO_AKCIPHER_ALG', + 'data': ['rsa', 'ecdsa']} + +## +# @QCryptoAkcipherKeyType: +# +# The type of asymmetric keys. +# +# Since: 7.0 +## +{ 'enum': 'QCryptoAkcipherKeyType', + 'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE', + 'data': ['public', 'private']} + +## +# @QCryptoRsaHashAlgorithm: +# +# The hash algorithm for RSA pkcs1 padding algothrim +# +# Since: 7.0 +## +{ 'enum': 'QCryptoRsaHashAlgorithm', + 'prefix': 'QCRYPTO_RSA_HASH_ALG', + 'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]} + +## +# @QCryptoRsaPaddingAlgorithm: +# +# The padding algorithm for RSA. +# +# @raw: no padding used +# @pkcs1: pkcs1#v1.5 +# +# Since: 7.0 +## +{ 'enum': 'QCryptoRsaPaddingAlgorithm', + 'prefix': 'QCRYPTO_RSA_PADDING_ALG', + 'data': ['raw', 'pkcs1']} + +## +# @QCryptoCurveId: +# +# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf +# +# Since: 7.0 +## +{ 'enum': 'QCryptoCurveId', + 'prefix': 'QCRYPTO_CURVE_ID', + 'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']} + +## +# @QCryptoRsaOptions: +# +# Specific parameters for RSA algorithm. +# +# @hash-algo: QCryptoRsaHashAlgorithm +# @padding-algo: QCryptoRsaPaddingAlgorithm +# +# Since: 7.0 +## +{ 'struct': 'QCryptoRsaOptions', + 'data': { 'hash-algo':'QCryptoRsaHashAlgorithm', + 'padding-algo': 'QCryptoRsaPaddingAlgorithm'}} + +## +# @QCryptoEcdsaOptions: +# +# Specific parameter for ECDSA algorithm. +# +# @curve-id: QCryptoCurveId +# +# Since: 7.0 +## +{ 'struct': 'QCryptoEcdsaOptions', + 'data': { 'curve-id': 'QCryptoCurveId' }} From patchwork Wed Mar 23 02:49:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: zhenwei pi X-Patchwork-Id: 553808 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 325CDC433EF for ; Wed, 23 Mar 2022 02:53:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235171AbiCWCyo (ORCPT ); Tue, 22 Mar 2022 22:54:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55138 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241402AbiCWCym (ORCPT ); Tue, 22 Mar 2022 22:54:42 -0400 Received: from mail-pl1-x632.google.com (mail-pl1-x632.google.com [IPv6:2607:f8b0:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AACB421E26 for ; Tue, 22 Mar 2022 19:53:12 -0700 (PDT) Received: by mail-pl1-x632.google.com with SMTP id n18so321053plg.5 for ; Tue, 22 Mar 2022 19:53:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=JRZKe62kNAZqIgMCGzGssCPXcTglMZ1LEDhPHI4EgMs=; b=IypQpgdPRPpyMzPYiFVdk4SjJxAR6xWFXaL0oi62SvwFsUezMboajpSgICc17w8bmF iwWJCN2+PE+V8eqOp9WP74/CU8EkIHQiCm15T7hz/2sZGNK3sR2LMRwRegCdB+Xwy9Lb UBVV3N8X0O3jnxZ06BgXhouXUV4rtduRgel36ahQTy7F6nljeYIxTt0ATGVIxr6Mam+Z spCc8kjtyWxO5SmApRiucMJTeOfM9rI7r55exrypsKGe2oPmdXeTGcLd75nDDN6dNpe6 ti2jCqWPC4/pSwj53tB9o6FLuW/a9GoFc1vMgKjpzbzxmhHqtCBdPpYryniXm1vKwBz9 pI/Q== 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=JRZKe62kNAZqIgMCGzGssCPXcTglMZ1LEDhPHI4EgMs=; b=K8wfMIV5OtJUKI3p9Y/Rtrh76272UfaMh86pwON1OI0H1C8HmfuUGKn8VSMe7QRkDB oQe6dXZdlbf0Cc19IA87lyEkmiCTeYp/JMdzlAHKLzGex6O4UdllPSmpmx8pVzNXw33D 9SK6Xqe+0rw8bjkP6cCfdtSySkt1pU8AdjUdYYHTLdDjSHy+ss/gW8iWBDwMm/85OAOG Jk3jXnirphpcrdVJrL+u82480i79UST5TPUBnU5tFyRWRgQVQP3RHWEYNQXDc19vwx/k 2OkNPF7Bs7So1CcSYf9bDWN/9txhE/arW1Mtxma9Z9ynN31Q4gY1wPiDmuWt5YLpWPpe E5TQ== X-Gm-Message-State: AOAM532UUiLTlUPX0PJBZ8UKq7/ZQj9tzyN3p8kcpclAmNn1LWuc0sru 03j84pEFs+G2eXMM6Pq1s/Mrng== X-Google-Smtp-Source: ABdhPJybYCZl672yipZaMz5UJ1+rO8Iv8eqh45OaimACaRtBPP+R1oTlrtlmMYr+x+hbmyHhm7oVSA== X-Received: by 2002:a17:902:e5cc:b0:154:1c96:2e5b with SMTP id u12-20020a170902e5cc00b001541c962e5bmr21368585plf.94.1648003992033; Tue, 22 Mar 2022 19:53:12 -0700 (PDT) Received: from always-x1.www.tendawifi.com ([139.177.225.224]) by smtp.gmail.com with ESMTPSA id t2-20020a63a602000000b0038062a0bc6fsm18104869pge.67.2022.03.22.19.53.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Mar 2022 19:53:11 -0700 (PDT) From: zhenwei pi To: arei.gonglei@huawei.com, mst@redhat.com Cc: jasowang@redhat.com, virtualization@lists.linux-foundation.org, qemu-devel@nongnu.org, linux-crypto@vger.kernel.org, herbert@gondor.apana.org.au, Lei He , zhenwei pi Subject: [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed Date: Wed, 23 Mar 2022 10:49:10 +0800 Message-Id: <20220323024912.249789-5-pizhenwei@bytedance.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220323024912.249789-1-pizhenwei@bytedance.com> References: <20220323024912.249789-1-pizhenwei@bytedance.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org From: Lei He Introduce ASN.1 decoder, and implement RSA algorithm by hogweed from nettle. Thus QEMU supports a 'real' RSA backend to handle request from guest side. It's important to test RSA offload case without OS & hardware requirement. Signed-off-by: lei he Signed-off-by: zhenwei pi --- crypto/akcipher-nettle.c | 523 ++++++++++++++++++++++++++++++++++++++ crypto/akcipher.c | 3 + crypto/asn1_decoder.c | 185 ++++++++++++++ crypto/asn1_decoder.h | 42 +++ crypto/meson.build | 3 + include/crypto/akcipher.h | 16 ++ meson.build | 11 + 7 files changed, 783 insertions(+) create mode 100644 crypto/akcipher-nettle.c create mode 100644 crypto/asn1_decoder.c create mode 100644 crypto/asn1_decoder.h diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c new file mode 100644 index 0000000000..45b93af772 --- /dev/null +++ b/crypto/akcipher-nettle.c @@ -0,0 +1,523 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include + +#include + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" +#include "asn1_decoder.h" +#include "crypto/akcipher.h" +#include "crypto/random.h" +#include "qapi/error.h" +#include "sysemu/cryptodev.h" + +typedef struct QCryptoNettleRsa { + QCryptoAkcipher akcipher; + struct rsa_public_key pub; + struct rsa_private_key priv; + QCryptoRsaPaddingAlgorithm padding_algo; + QCryptoRsaHashAlgorithm hash_algo; +} QCryptoNettleRsa; + +struct asn1_parse_ctx { + const uint8_t *data; + size_t dlen; +}; + +#define Octet 8 + +static int extract_value(void *p, const uint8_t *data, size_t dlen) +{ + struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p; + ctx->data = (uint8_t *)data; + ctx->dlen = dlen; + + return 0; +} + +static int extract_mpi(void *p, const uint8_t *data, size_t dlen) +{ + mpz_t *target = (mpz_t *)p; + nettle_mpz_set_str_256_u(*target, dlen, data); + + return 0; +} + +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void); + +static void qcrypto_nettle_rsa_destroy(void *ptr) +{ + QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr; + if (!rsa) { + return; + } + + rsa_public_key_clear(&rsa->pub); + rsa_private_key_clear(&rsa->priv); + g_free(rsa); +} + +static QCryptoAkcipher *qcrypto_nettle_new_rsa( + QCryptoAkcipherKeyType type, + const uint8_t *key, size_t keylen, + QCryptoRsaOptions *opt, Error **errp); + +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg, + QCryptoAkcipherKeyType type, + const uint8_t *key, + size_t keylen, void *para, + Error **errp) +{ + switch (alg) { + case QCRYPTO_AKCIPHER_ALG_RSA: + return qcrypto_nettle_new_rsa(type, key, keylen, + (QCryptoRsaOptions *)para, errp); + default: + error_setg(errp, "Unsupported algorithm: %u", alg); + return NULL; + } + + return NULL; +} + +/** + * Parse ber encoded rsa private key, asn1 schema: + * RsaPrivKey ::= SEQUENCE { + * version INTEGER + * n INTEGER + * e INTEGER + * d INTEGER + * p INTEGER + * q INTEGER + * e1 INTEGER + * e2 INTEGER + * u INTEGER + * } + */ +static int parse_rsa_private_key(QCryptoNettleRsa *rsa, + const uint8_t *key, size_t keylen) +{ + struct asn1_parse_ctx ctx; + + if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 || + keylen != 0) { + return -1; + } + + if (ber_decode_int(&ctx.data, &ctx.dlen, NULL, NULL) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.d) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.p) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.q) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.a) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.b) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->priv.c) != 0 || + ctx.dlen != 0) { + return -1; + } + + if (!rsa_public_key_prepare(&rsa->pub)) { + return -1; + } + + /** + * Since in the kernel's unit test, the p, q, a, b, c of some + * private keys is 0, only the simplest length check is done here + */ + rsa->priv.size = rsa->pub.size; + + return 0; +} + +/** + * Parse ber encoded rsa pubkey, asn1 schema: + * RsaPrivKey ::= SEQUENCE { + * n INTEGER + * e INTEGER + * } + */ +static int parse_rsa_public_key(QCryptoNettleRsa *rsa, + const uint8_t *key, + size_t keylen) +{ + struct asn1_parse_ctx ctx; + + if (ber_decode_seq(&key, &keylen, extract_value, &ctx) != 0 || + keylen != 0) { + return -1; + } + + if (ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.n) != 0 || + ber_decode_int(&ctx.data, &ctx.dlen, extract_mpi, &rsa->pub.e) != 0 || + ctx.dlen != 0) { + return -1; + } + + if (!rsa_public_key_prepare(&rsa->pub)) { + return -1; + } + + return 0; +} + +static void qcrypto_nettle_rsa_set_akcipher_size(QCryptoAkcipher *akcipher, + int key_size) +{ + akcipher->max_plaintext_len = key_size; + akcipher->max_ciphertext_len = key_size; + akcipher->max_signature_len = key_size; + akcipher->max_dgst_len = key_size; +} + +static QCryptoAkcipher *qcrypto_nettle_new_rsa( + QCryptoAkcipherKeyType type, + const uint8_t *key, size_t keylen, + QCryptoRsaOptions *opt, Error **errp) +{ + QCryptoNettleRsa *rsa = qcrypto_nettle_rsa_malloc(); + rsa->padding_algo = opt->padding_algo; + rsa->hash_algo = opt->hash_algo; + + switch (type) { + case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + if (parse_rsa_private_key(rsa, key, keylen) == 0) { + qcrypto_nettle_rsa_set_akcipher_size( + (QCryptoAkcipher *)rsa, rsa->priv.size); + return (QCryptoAkcipher *)rsa; + } + error_setg(errp, "Failed to parse rsa private key"); + break; + + case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + if (parse_rsa_public_key(rsa, key, keylen) == 0) { + qcrypto_nettle_rsa_set_akcipher_size( + (QCryptoAkcipher *)rsa, rsa->pub.size); + return (QCryptoAkcipher *)rsa; + } + error_setg(errp, "Failed to parse rsa public rsa key"); + break; + + default: + error_setg(errp, "Unknown akcipher key type %d", type); + } + + qcrypto_nettle_rsa_destroy(rsa); + return NULL; +} + + +/** + * nettle does not provide RSA interfaces without padding, + * here we implemented rsa algorithm with nettle/mpz. + */ +static int _rsa_enc_raw(QCryptoNettleRsa *rsa, const void *data, + size_t data_len, void *enc, + size_t enc_len, Error **errp) +{ + mpz_t m; + int ret; + + nettle_mpz_init_set_str_256_u(m, data_len, data); + /* (1) Validate 0 <= m < n */ + if (mpz_cmp_ui(m, 0) < 0 || mpz_cmp(m, rsa->pub.n) >= 0) { + error_setg(errp, "Failed to validate input data"); + return -1; + } + + /* (2) c = m ^ e mod n */ + mpz_powm(m, m, rsa->pub.e, rsa->pub.n); + if ((mpz_sizeinbase(m, 2) + Octet - 1) / Octet > enc_len) { + ret = -1; + } else { + ret = enc_len; + nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, m); + } + + mpz_clear(m); + + return ret; +} + +static int _rsa_dec_raw(QCryptoNettleRsa *rsa, + const void *enc, + size_t enc_len, + void *data, + size_t data_len, + Error **errp) +{ + mpz_t c; + int ret; + nettle_mpz_init_set_str_256_u(c, enc_len, enc); + + /* (1) Validate 0 <= c < n */ + if (mpz_cmp_ui(c, 0) < 0 || mpz_cmp(c, rsa->pub.n) >= 0) { + error_setg(errp, "Failed to validate input data"); + return -1; + } + + /* (2) m = c ^ d mod n */ + mpz_powm(c, c, rsa->priv.d, rsa->pub.n); + if ((mpz_sizeinbase(c, 2) + Octet - 1) / Octet > data_len) { + ret = -1; + } else { + ret = data_len; + nettle_mpz_get_str_256(data_len, (uint8_t *)data, c); + } + + mpz_clear(c); + + return ret; +} + +static void wrap_nettle_random_func(void *ctx, size_t len, uint8_t *out) +{ + /* TODO: check result */ + qcrypto_random_bytes(out, len, NULL); +} + +static int qcrypto_nettle_rsa_encrypt(QCryptoAkcipher *akcipher_driver, + const void *data, size_t data_len, + void *enc, size_t enc_len, + Error **errp) +{ + + QCryptoNettleRsa *rsa = + container_of(akcipher_driver, QCryptoNettleRsa, akcipher); + mpz_t c; + int enc_ret; + + if (data_len > rsa->pub.size || enc_len != rsa->pub.size) { + error_setg(errp, "Invalid buffer size"); + return -1; + } + + switch (rsa->padding_algo) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + return _rsa_enc_raw(rsa, data, data_len, enc, enc_len, errp); + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + mpz_init(c); + enc_ret = rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func, + data_len, (uint8_t *)data, c); + if (enc_ret != 1) { + error_setg(errp, "Failed to encrypt"); + enc_ret = -1; + } else { + nettle_mpz_get_str_256(enc_len, (uint8_t *)enc, c); + enc_ret = enc_len; + } + mpz_clear(c); + return enc_ret; + + default: + error_setg(errp, "Unknown padding"); + return -1; + } + + return -1; +} + +static int qcrypto_nettle_rsa_decrypt(QCryptoAkcipher *akcipher, + const void *enc, size_t enc_len, + void *data, size_t data_len, + Error **errp) +{ + QCryptoNettleRsa *rsa = container_of(akcipher, QCryptoNettleRsa, akcipher); + mpz_t c; + int ret; + if (enc_len > rsa->priv.size) { + error_setg(errp, "Invalid buffer size"); + return -1; + } + + switch (rsa->padding_algo) { + case QCRYPTO_RSA_PADDING_ALG_RAW: + ret = _rsa_dec_raw(rsa, enc, enc_len, data, data_len, errp); + break; + + case QCRYPTO_RSA_PADDING_ALG_PKCS1: + nettle_mpz_init_set_str_256_u(c, enc_len, enc); + if (!rsa_decrypt(&rsa->priv, &data_len, (uint8_t *)data, c)) { + error_setg(errp, "Failed to decrypt"); + ret = -1; + } else { + ret = data_len; + } + + mpz_clear(c); + break; + + default: + ret = -1; + error_setg(errp, "Unknown padding"); + } + + return ret; +} + +static int qcrypto_nettle_rsa_sign(QCryptoAkcipher *akcipher, + const void *data, size_t data_len, + void *sig, size_t sig_len, Error **errp) +{ + QCryptoNettleRsa *rsa = container_of(akcipher, QCryptoNettleRsa, akcipher); + int ret; + mpz_t s; + + /** + * The RSA algorithm cannot be used for signature/verification + * without padding. + */ + if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) { + error_setg(errp, "Try to make signature without padding"); + return -1; + } + + if (data_len > rsa->priv.size || sig_len != rsa->priv.size) { + error_setg(errp, "Invalid buffer size"); + return -1; + } + + mpz_init(s); + switch (rsa->hash_algo) { + case QCRYPTO_RSA_HASH_ALG_MD5: + ret = rsa_md5_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_RSA_HASH_ALG_SHA1: + ret = rsa_sha1_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_RSA_HASH_ALG_SHA256: + ret = rsa_sha256_sign_digest(&rsa->priv, data, s); + break; + + case QCRYPTO_RSA_HASH_ALG_SHA512: + ret = rsa_sha512_sign_digest(&rsa->priv, data, s); + break; + + default: + error_setg(errp, "Unknown hash algorithm"); + ret = -1; + goto clear; + } + + if (ret != 1) { + error_setg(errp, "Failed to make signature"); + ret = -1; + goto clear; + } + nettle_mpz_get_str_256(sig_len, (uint8_t *)sig, s); + ret = sig_len; + +clear: + mpz_clear(s); + + return ret; +} + +static int qcrypto_nettle_rsa_verify(QCryptoAkcipher *akcipher, + const void *sig, size_t sig_len, + const void *data, size_t data_len, + Error **errp) +{ + QCryptoNettleRsa *rsa = container_of(akcipher, QCryptoNettleRsa, akcipher); + + int ret; + mpz_t s; + + /** + * The RSA algorithm cannot be used for signature/verification + * without padding. + */ + if (rsa->padding_algo == QCRYPTO_RSA_PADDING_ALG_RAW) { + error_setg(errp, "Operation not supported"); + return -1; + } + if (data_len > rsa->pub.size || sig_len < rsa->pub.size) { + error_setg(errp, "Invalid buffer size"); + return -1; + } + + nettle_mpz_init_set_str_256_u(s, sig_len, sig); + switch (rsa->hash_algo) { + case QCRYPTO_RSA_HASH_ALG_MD5: + ret = rsa_md5_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_RSA_HASH_ALG_SHA1: + ret = rsa_sha1_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_RSA_HASH_ALG_SHA256: + ret = rsa_sha256_verify_digest(&rsa->pub, data, s); + break; + + case QCRYPTO_RSA_HASH_ALG_SHA512: + ret = rsa_sha512_verify_digest(&rsa->pub, data, s); + break; + + default: + error_setg(errp, "Unsupported hash algorithm"); + ret = -1; + goto clear; + } + + if (ret != 1) { + error_setg(errp, "Failed to verify"); + ret = -1; + goto clear; + } + ret = 0; + +clear: + mpz_clear(s); + + return ret; +} + +static int qcrypto_nettle_rsa_free(struct QCryptoAkcipher *akcipher, + Error **errp) +{ + qcrypto_nettle_rsa_destroy(akcipher); + return 0; +} + +QCryptoAkcipherDriver nettle_rsa = { + .encrypt = qcrypto_nettle_rsa_encrypt, + .decrypt = qcrypto_nettle_rsa_decrypt, + .sign = qcrypto_nettle_rsa_sign, + .verify = qcrypto_nettle_rsa_verify, + .free = qcrypto_nettle_rsa_free, +}; + +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void) +{ + QCryptoNettleRsa *rsa = g_malloc0(sizeof(QCryptoNettleRsa)); + memset(rsa, 0, sizeof(QCryptoNettleRsa)); + rsa->akcipher.driver = &nettle_rsa; + rsa_public_key_init(&rsa->pub); + rsa_private_key_init(&rsa->priv); + + return rsa; +} diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 1e52f2fd76..b5c04e8424 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -31,6 +31,9 @@ QCryptoAkcipher *qcrypto_akcipher_new(QCryptoAkcipherAlgorithm alg, { QCryptoAkcipher *akcipher = NULL; + akcipher = qcrypto_akcipher_nettle_new(alg, type, key, keylen, + para, errp); + return akcipher; } diff --git a/crypto/asn1_decoder.c b/crypto/asn1_decoder.c new file mode 100644 index 0000000000..bfb145e84e --- /dev/null +++ b/crypto/asn1_decoder.c @@ -0,0 +1,185 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include +#include + +#include "crypto/asn1_decoder.h" + +enum ber_type_tag { + ber_type_tag_bool = 0x1, + ber_type_tag_int = 0x2, + ber_type_tag_bit_str = 0x3, + ber_type_tag_oct_str = 0x4, + ber_type_tag_oct_null = 0x5, + ber_type_tag_oct_oid = 0x6, + ber_type_tag_seq = 0x10, + ber_type_tag_set = 0x11, +}; + +#define BER_CONSTRUCTED_MASK 0x20 +#define BER_SHORT_LEN_MASK 0x80 + +static uint8_t ber_peek_byte(const uint8_t **data, size_t *dlen) +{ + return **data; +} + +static int invoke_callback(BerDecodeCb cb, void *ctx, + const uint8_t *value, size_t vlen) +{ + if (!cb) { + return 0; + } + + return cb(ctx, value, vlen); +} + +static void ber_cut_nbytes(const uint8_t **data, size_t *dlen, + size_t nbytes) +{ + *data += nbytes; + *dlen -= nbytes; +} + +static uint8_t ber_cut_byte(const uint8_t **data, size_t *dlen) +{ + uint8_t val = ber_peek_byte(data, dlen); + + ber_cut_nbytes(data, dlen, 1); + + return val; +} + +static int ber_extract_definite_data(const uint8_t **data, size_t *dlen, + BerDecodeCb cb, void *ctx) +{ + const uint8_t *value; + size_t vlen = 0; + uint8_t byte_count = ber_cut_byte(data, dlen); + + /* short format of definite-length */ + if (!(byte_count & BER_SHORT_LEN_MASK)) { + if (byte_count > *dlen) { + return -1; + } + + value = *data; + vlen = byte_count; + ber_cut_nbytes(data, dlen, vlen); + + return invoke_callback(cb, ctx, value, vlen); + } + + /* Ignore highest bit */ + byte_count &= ~BER_SHORT_LEN_MASK; + + /* + * size_t is enough to express the length, although the ber encoding + * standard supports larger length. + */ + if (byte_count > sizeof(size_t)) { + return -1; + } + + while (byte_count--) { + vlen <<= 8; + vlen += ber_cut_byte(data, dlen); + } + + if (vlen > *dlen) { + return -1; + } + + value = *data; + ber_cut_nbytes(data, dlen, vlen); + + return invoke_callback(cb, ctx, value, vlen); +} + +static int ber_extract_undefinite_data(const uint8_t **data, size_t *dlen, + BerDecodeCb cb, void *ctx) +{ + size_t vlen = 0; + const uint8_t *value; + + if (*dlen < 3) { + return -1; + } + + /* skip undefinite-length-mask 0x80 */ + ber_cut_nbytes(data, dlen, 1); + + value = *data; + while (vlen < *dlen) { + if ((*data)[vlen] != 0) { + vlen++; + continue; + } + + if (vlen + 1 < *dlen && (*data[vlen + 1] == 0)) { + ber_cut_nbytes(data, dlen, vlen + 2); + return invoke_callback(cb, ctx, value, vlen); + } + + vlen += 2; + } + + return -1; +} + +static int ber_extract_data(const uint8_t **data, size_t *dlen, + BerDecodeCb cb, void *ctx) +{ + uint8_t val = ber_peek_byte(data, dlen); + + if (val == BER_SHORT_LEN_MASK) { + return ber_extract_undefinite_data(data, dlen, cb, ctx); + } + + return ber_extract_definite_data(data, dlen, cb, ctx); +} + +int ber_decode_int(const uint8_t **data, size_t *dlen, + BerDecodeCb cb, void *ctx) +{ + uint8_t tag = ber_cut_byte(data, dlen); + + /* INTEGER must encoded in primitive-form */ + if (tag != ber_type_tag_int) { + return -1; + } + + return ber_extract_data(data, dlen, cb, ctx); +} + +int ber_decode_seq(const uint8_t **data, size_t *dlen, + BerDecodeCb cb, void *ctx) +{ + uint8_t val = ber_cut_byte(data, dlen); + + /* SEQUENCE must use constructed form */ + if (val != (ber_type_tag_seq | BER_CONSTRUCTED_MASK)) { + return -1; + } + + return ber_extract_data(data, dlen, cb, ctx); +} diff --git a/crypto/asn1_decoder.h b/crypto/asn1_decoder.h new file mode 100644 index 0000000000..d33a7c81c4 --- /dev/null +++ b/crypto/asn1_decoder.h @@ -0,0 +1,42 @@ +/* + * QEMU Crypto akcipher algorithms + * + * Copyright (c) 2022 Bytedance + * Author: lei he + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#ifndef QCRYPTO_ASN1_DECODER_H +#define QCRYPTO_ASN1_DECODER_H + +/* + * ctx: user content. + * value: the starting address of |value| part of 'Tag-Length-Value' pattern. + * vlen: length of the |value|. + */ +typedef int (*BerDecodeCb) (void *ctx, const uint8_t *value, size_t vlen); + +int ber_decode_int(const uint8_t **data, + size_t *dlen, + BerDecodeCb cb, + void *ctx); + +int ber_decode_seq(const uint8_t **data, + size_t *dlen, + BerDecodeCb cb, + void *ctx); + +#endif /* QCRYPTO_ASN1_DECODER_H */ diff --git a/crypto/meson.build b/crypto/meson.build index c32b57aeda..f398d7abda 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -27,6 +27,9 @@ if nettle.found() if xts == 'private' crypto_ss.add(files('xts.c')) endif + if hogweed.found() + crypto_ss.add(gmp, hogweed, files('akcipher-nettle.c', 'asn1_decoder.c')) + endif elif gcrypt.found() crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c')) elif gnutls_crypto.found() diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index 03cc3bf46b..2ec7f0f8d7 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -135,5 +135,21 @@ int qcrypto_akcipher_verify(struct QCryptoAkcipher *akcipher, int qcrypto_akcipher_free(struct QCryptoAkcipher *akcipher, Error **errp); +#ifdef CONFIG_HOGWEED +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg, + QCryptoAkcipherKeyType type, + const uint8_t *key, size_t keylen, + void *para, Error **errp); +#else +static inline QCryptoAkcipher *qcrypto_akcipher_nettle_new( + QCryptoAkcipherAlgorithm alg, + QCryptoAkcipherKeyType type, + const uint8_t *key, size_t keylen, + void *para, Error **errp) +{ + error_setg(errp, "qcrypto akcipher has no nettle/hogweed support"); + return NULL; +} +#endif #endif /* QCRYPTO_AKCIPHER_H */ diff --git a/meson.build b/meson.build index 282e7c4650..ea6b8feb3c 100644 --- a/meson.build +++ b/meson.build @@ -1049,6 +1049,7 @@ endif # gcrypt over nettle for performance reasons. gcrypt = not_found nettle = not_found +hogweed = not_found xts = 'none' if get_option('nettle').enabled() and get_option('gcrypt').enabled() @@ -1086,6 +1087,14 @@ if not gnutls_crypto.found() endif endif +gmp = dependency('gmp', required: false, method: 'pkg-config', kwargs: static_kwargs) +if nettle.found() and gmp.found() + hogweed = dependency('hogweed', version: '>=3.4', + method: 'pkg-config', + required: get_option('nettle'), + kwargs: static_kwargs) +endif + gtk = not_found gtkx11 = not_found vte = not_found @@ -1567,6 +1576,7 @@ config_host_data.set('CONFIG_GNUTLS', gnutls.found()) config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found()) config_host_data.set('CONFIG_GCRYPT', gcrypt.found()) config_host_data.set('CONFIG_NETTLE', nettle.found()) +config_host_data.set('CONFIG_HOGWEED', hogweed.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) config_host_data.set('CONFIG_STATX', has_statx) @@ -3614,6 +3624,7 @@ summary_info += {'libgcrypt': gcrypt} summary_info += {'nettle': nettle} if nettle.found() summary_info += {' XTS': xts != 'private'} + summary_info += {' hogweed': hogweed.found()} endif summary_info += {'AF_ALG support': have_afalg} summary_info += {'rng-none': get_option('rng_none')} From patchwork Wed Mar 23 02:49:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: zhenwei pi X-Patchwork-Id: 553807 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 766A0C433F5 for ; Wed, 23 Mar 2022 02:54:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231129AbiCWCzo (ORCPT ); Tue, 22 Mar 2022 22:55:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55602 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241406AbiCWCyx (ORCPT ); Tue, 22 Mar 2022 22:54:53 -0400 Received: from mail-pl1-x631.google.com (mail-pl1-x631.google.com [IPv6:2607:f8b0:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 82EB226AD4 for ; Tue, 22 Mar 2022 19:53:22 -0700 (PDT) Received: by mail-pl1-x631.google.com with SMTP id q5so325056plg.3 for ; Tue, 22 Mar 2022 19:53:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bytedance-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yAt/yS+DcoOp9kEJuurD0eo4HQA/l5xN8mV4xo1cmLI=; b=WpDpKZ+D1RZ1WLXG8C5DPz7KEzbfg/rbJjxGfP9ca4AC3Sm4jmbRG3h557CoSGQjUp NpIT9xZnP5i5G2/hhu8UvtYW/FeuwKjvd9+hnJwSeq0RQ/BQQbJnrX8QXzTXQKTqFx47 pvHRpbwn7rnssB1OCYvSXLPuZBOWD8zuqRqL6RAbDj3osOfTuI3wIxSFdLN07jPU2vb9 kBWYHJAT6uTJjZIhQdASpwNGPWQqsF3GYARDu6osSSto9fkKoBeAfidNECGPmQJ4/SgH rJCG37LiRSTrf9xD1SfY5ifQkNUHMoR//pq5wWbneJ9gVBa3OcCPq1uwGoQyBx4p/2kG QhBA== 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=yAt/yS+DcoOp9kEJuurD0eo4HQA/l5xN8mV4xo1cmLI=; b=ttgB7toCml03xkGnUEb4KB49jUX+O/tmeGBWcuAuwIL3TLkue1RjyF1kTJ23b4ft8v u+j3SplkV4riDUnY5TCBMj1mtYuEBHBJyv5ykSY+oA457GMqmUz0iVmmLDo0/EjQ3XOq c1b0NrqjrZ3AxtnDRZNEsVGLIf2hqG4x1hpGKYx/PuAGT5YS/b2o8MXHEo0Pac6e+6C2 rjP4Wbd5/FhlZ+OFhzTJvYExHHm7+mi60/2cQZrHc+k0B2Hr/Ktj/m0zNl9eUIpMX3cL kiI5xiqlGYsuDYw2nUeufi/8OgHcekXD9GWOAjtHz+tEmaaixTRVFye3ZlvKYE07urc5 bIAg== X-Gm-Message-State: AOAM532UvNG+kGS7RXg52f4ed72KhWqfADa/V0TzjJQx4P3aOBoxLW7D c/PK2u2UqZIcKAwXSRmn3zcpuA== X-Google-Smtp-Source: ABdhPJxnQsaXFwj3Zl8Q7GZMgS49wAnnSRP9jEk0kbSaeZz0fyjXweJWOg7H0EM9JidUz/3oVg3wIQ== X-Received: by 2002:a17:903:404b:b0:154:297b:7125 with SMTP id n11-20020a170903404b00b00154297b7125mr20411444pla.11.1648004001810; Tue, 22 Mar 2022 19:53:21 -0700 (PDT) Received: from always-x1.www.tendawifi.com ([139.177.225.224]) by smtp.gmail.com with ESMTPSA id t2-20020a63a602000000b0038062a0bc6fsm18104869pge.67.2022.03.22.19.53.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Mar 2022 19:53:21 -0700 (PDT) From: zhenwei pi To: arei.gonglei@huawei.com, mst@redhat.com Cc: jasowang@redhat.com, virtualization@lists.linux-foundation.org, qemu-devel@nongnu.org, linux-crypto@vger.kernel.org, herbert@gondor.apana.org.au, zhenwei pi Subject: [PATCH v3 6/6] virtio-crypto: Introduce RSA algorithm Date: Wed, 23 Mar 2022 10:49:12 +0800 Message-Id: <20220323024912.249789-7-pizhenwei@bytedance.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220323024912.249789-1-pizhenwei@bytedance.com> References: <20220323024912.249789-1-pizhenwei@bytedance.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org There are two parts in this patch: 1, support akcipher service by cryptodev-builtin driver 2, virtio-crypto driver supports akcipher service Then virtio-crypto gets request from guest side, and forwards the request to builtin driver to handle it. Test with a guest linux: 1, The self-test framework of crypto layer works fine in guest kernel 2, Test with Linux guest(with asym support), the following script test(note that pkey_XXX is supported only in a newer version of keyutils): - both public key & private key - create/close session - encrypt/decrypt/sign/verify basic driver operation - also test with kernel crypto layer(pkey add/query) All the cases work fine. Run script in guest: rm -rf *.der *.pem *.pfx modprobe pkcs8_key_parser # if CONFIG_PKCS8_PRIVATE_KEY_PARSER=m rm -rf /tmp/data dd if=/dev/random of=/tmp/data count=1 bs=226 openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -subj "/C=CN/ST=BJ/L=HD/O=qemu/OU=dev/CN=qemu/emailAddress=qemu@qemu.org" openssl pkcs8 -in key.pem -topk8 -nocrypt -outform DER -out key.der openssl x509 -in cert.pem -inform PEM -outform DER -out cert.der PRIV_KEY_ID=`cat key.der | keyctl padd asymmetric test_priv_key @s` echo "priv key id = "$PRIV_KEY_ID PUB_KEY_ID=`cat cert.der | keyctl padd asymmetric test_pub_key @s` echo "pub key id = "$PUB_KEY_ID keyctl pkey_query $PRIV_KEY_ID 0 keyctl pkey_query $PUB_KEY_ID 0 echo "Enc with priv key..." keyctl pkey_encrypt $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.priv echo "Dec with pub key..." keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.priv enc=pkcs1 >/tmp/dec cmp /tmp/data /tmp/dec echo "Sign with priv key..." keyctl pkey_sign $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 hash=sha1 > /tmp/sig echo "Verify with pub key..." keyctl pkey_verify $PRIV_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1 echo "Enc with pub key..." keyctl pkey_encrypt $PUB_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.pub echo "Dec with priv key..." keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.pub enc=pkcs1 >/tmp/dec cmp /tmp/data /tmp/dec echo "Verify with pub key..." keyctl pkey_verify $PUB_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1 Co-developed-by: lei he Signed-off-by: lei he conf.crypto_services = 1u << VIRTIO_CRYPTO_SERVICE_CIPHER | 1u << VIRTIO_CRYPTO_SERVICE_HASH | - 1u << VIRTIO_CRYPTO_SERVICE_MAC; + 1u << VIRTIO_CRYPTO_SERVICE_MAC | + 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER; backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC; backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1; + backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA; /* * Set the Maximum length of crypto request. * Why this value? Just avoid to overflow when * memory allocation for each crypto request. */ - backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo); + backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo); backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN; backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN; @@ -148,6 +152,100 @@ err: return -1; } +static int cryptodev_builtin_get_rsa_hash_algo( + int virtio_rsa_hash, Error **errp) +{ + switch (virtio_rsa_hash) { + case VIRTIO_CRYPTO_RSA_MD2: + return QCRYPTO_RSA_HASH_ALG_MD2; + + case VIRTIO_CRYPTO_RSA_MD3: + return QCRYPTO_RSA_HASH_ALG_MD3; + + case VIRTIO_CRYPTO_RSA_MD4: + return QCRYPTO_RSA_HASH_ALG_MD4; + + case VIRTIO_CRYPTO_RSA_MD5: + return QCRYPTO_RSA_HASH_ALG_MD5; + + case VIRTIO_CRYPTO_RSA_SHA1: + return QCRYPTO_RSA_HASH_ALG_SHA1; + + case VIRTIO_CRYPTO_RSA_SHA256: + return QCRYPTO_RSA_HASH_ALG_SHA256; + + case VIRTIO_CRYPTO_RSA_SHA384: + return QCRYPTO_RSA_HASH_ALG_SHA384; + + case VIRTIO_CRYPTO_RSA_SHA512: + return QCRYPTO_RSA_HASH_ALG_SHA512; + + case VIRTIO_CRYPTO_RSA_SHA224: + return QCRYPTO_RSA_HASH_ALG_SHA224; + + default: + error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash); + return -1; + } +} + +static int cryptodev_builtin_set_rsa_options( + int virtio_padding_algo, + int virtio_hash_algo, + QCryptoRsaOptions *opt, + Error **errp) +{ + if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) { + opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1; + opt->hash_algo = + cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp); + if (opt->hash_algo < 0) { + return -1; + } + return 0; + } + + if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) { + opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW; + return 0; + } + + error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo); + return -1; +} + +static int cryptodev_builtin_set_ecdsa_options(int virtio_curve_id, + QCryptoEcdsaOptions *opt, Error **errp) +{ + switch (virtio_curve_id) { + case VIRTIO_CRYPTO_CURVE_NIST_P192: + opt->curve_id = QCRYPTO_CURVE_ID_NIST_P192; + break; + + case VIRTIO_CRYPTO_CURVE_NIST_P224: + opt->curve_id = QCRYPTO_CURVE_ID_NIST_P224; + break; + + case VIRTIO_CRYPTO_CURVE_NIST_P256: + opt->curve_id = QCRYPTO_CURVE_ID_NIST_P256; + break; + + case VIRTIO_CRYPTO_CURVE_NIST_P384: + opt->curve_id = QCRYPTO_CURVE_ID_NIST_P384; + break; + + case VIRTIO_CRYPTO_CURVE_NIST_P521: + opt->curve_id = QCRYPTO_CURVE_ID_NIST_P521; + break; + + default: + error_setg(errp, "Unsupported curve id: %d", virtio_curve_id); + return -1; + } + + return 0; +} + static int cryptodev_builtin_create_cipher_session( CryptoDevBackendBuiltin *builtin, CryptoDevBackendSymSessionInfo *sess_info, @@ -240,26 +338,100 @@ static int cryptodev_builtin_create_cipher_session( return index; } -static int64_t cryptodev_builtin_sym_create_session( +static int cryptodev_builtin_create_akcipher_session( + CryptoDevBackendBuiltin *builtin, + CryptoDevBackendAsymSessionInfo *sess_info, + Error **errp) +{ + CryptoDevBackendBuiltinSession *sess; + QCryptoAkcipher *akcipher; + int index; + QCryptoAkcipherAlgorithm alg; + QCryptoAkcipherKeyType type; + QCryptoRsaOptions rsa_opt; + QCryptoEcdsaOptions ecdsa_opt; + void *opt; + + switch (sess_info->algo) { + case VIRTIO_CRYPTO_AKCIPHER_RSA: + alg = QCRYPTO_AKCIPHER_ALG_RSA; + if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo, + sess_info->u.rsa.hash_algo, &rsa_opt, errp) != 0) { + return -1; + } + opt = (void *)&rsa_opt; + break; + + case VIRTIO_CRYPTO_AKCIPHER_ECDSA: + alg = QCRYPTO_AKCIPHER_ALG_ECDSA; + if (cryptodev_builtin_set_ecdsa_options(sess_info->u.ecdsa.curve_id, + &ecdsa_opt, errp) != 0) { + return -1; + } + opt = (void *)&ecdsa_opt; + break; + + default: + error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo); + return -1; + } + + switch (sess_info->keytype) { + case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC: + type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC; + break; + + case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE: + type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE; + break; + + default: + error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype); + return -1; + } + + index = cryptodev_builtin_get_unused_session_index(builtin); + if (index < 0) { + error_setg(errp, "Total number of sessions created exceeds %u", + MAX_NUM_SESSIONS); + return -1; + } + + akcipher = qcrypto_akcipher_new(alg, type, sess_info->key, + sess_info->keylen, opt, errp); + if (!akcipher) { + return -1; + } + + sess = g_new0(CryptoDevBackendBuiltinSession, 1); + sess->akcipher = akcipher; + + builtin->sessions[index] = sess; + + return index; +} + +static int64_t cryptodev_builtin_create_session( CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, + CryptoDevBackendSessionInfo *sess_info, uint32_t queue_index, Error **errp) { CryptoDevBackendBuiltin *builtin = CRYPTODEV_BACKEND_BUILTIN(backend); - int64_t session_id = -1; - int ret; + CryptoDevBackendSymSessionInfo *sym_sess_info; + CryptoDevBackendAsymSessionInfo *asym_sess_info; switch (sess_info->op_code) { case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: - ret = cryptodev_builtin_create_cipher_session( - builtin, sess_info, errp); - if (ret < 0) { - return ret; - } else { - session_id = ret; - } - break; + sym_sess_info = &sess_info->u.sym_sess_info; + return cryptodev_builtin_create_cipher_session( + builtin, sym_sess_info, errp); + + case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: + asym_sess_info = &sess_info->u.asym_sess_info; + return cryptodev_builtin_create_akcipher_session( + builtin, asym_sess_info, errp); + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: case VIRTIO_CRYPTO_MAC_CREATE_SESSION: default: @@ -268,10 +440,10 @@ static int64_t cryptodev_builtin_sym_create_session( return -1; } - return session_id; + return -1; } -static int cryptodev_builtin_sym_close_session( +static int cryptodev_builtin_close_session( CryptoDevBackend *backend, uint64_t session_id, uint32_t queue_index, Error **errp) @@ -288,30 +460,17 @@ static int cryptodev_builtin_sym_close_session( } static int cryptodev_builtin_sym_operation( - CryptoDevBackend *backend, - CryptoDevBackendSymOpInfo *op_info, - uint32_t queue_index, Error **errp) + CryptoDevBackendBuiltinSession *sess, + CryptoDevBackendSymOpInfo *op_info, Error **errp) { - CryptoDevBackendBuiltin *builtin = - CRYPTODEV_BACKEND_BUILTIN(backend); - CryptoDevBackendBuiltinSession *sess; int ret; - if (op_info->session_id >= MAX_NUM_SESSIONS || - builtin->sessions[op_info->session_id] == NULL) { - error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", - op_info->session_id); - return -VIRTIO_CRYPTO_INVSESS; - } - if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { error_setg(errp, "Algorithm chain is unsupported for cryptdoev-builtin"); return -VIRTIO_CRYPTO_NOTSUPP; } - sess = builtin->sessions[op_info->session_id]; - if (op_info->iv_len > 0) { ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv, op_info->iv_len, errp); @@ -333,9 +492,95 @@ static int cryptodev_builtin_sym_operation( return -VIRTIO_CRYPTO_ERR; } } + + return VIRTIO_CRYPTO_OK; +} + +static int cryptodev_builtin_asym_operation( + CryptoDevBackendBuiltinSession *sess, uint32_t op_code, + CryptoDevBackendAsymOpInfo *op_info, Error **errp) +{ + int ret; + + switch (op_code) { + case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: + ret = qcrypto_akcipher_encrypt(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: + ret = qcrypto_akcipher_decrypt(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + case VIRTIO_CRYPTO_AKCIPHER_SIGN: + ret = qcrypto_akcipher_sign(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + case VIRTIO_CRYPTO_AKCIPHER_VERIFY: + ret = qcrypto_akcipher_verify(sess->akcipher, + op_info->src, op_info->src_len, + op_info->dst, op_info->dst_len, errp); + break; + + default: + return -VIRTIO_CRYPTO_ERR; + } + + if (ret < 0) { + if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { + return -VIRTIO_CRYPTO_KEY_REJECTED; + } + return -VIRTIO_CRYPTO_ERR; + } + + /* Buffer is too short */ + if (unlikely(ret > op_info->dst_len)) { + return -VIRTIO_CRYPTO_ERR; + } + + op_info->dst_len = ret; + return VIRTIO_CRYPTO_OK; } +static int cryptodev_builtin_operation( + CryptoDevBackend *backend, + CryptoDevBackendOpInfo *op_info, + uint32_t queue_index, Error **errp) +{ + CryptoDevBackendBuiltin *builtin = + CRYPTODEV_BACKEND_BUILTIN(backend); + CryptoDevBackendBuiltinSession *sess; + CryptoDevBackendSymOpInfo *sym_op_info; + CryptoDevBackendAsymOpInfo *asym_op_info; + enum CryptoDevBackendAlgType algtype = op_info->algtype; + int ret = -VIRTIO_CRYPTO_ERR; + + if (op_info->session_id >= MAX_NUM_SESSIONS || + builtin->sessions[op_info->session_id] == NULL) { + error_setg(errp, "Cannot find a valid session id: %" PRIu64 "", + op_info->session_id); + return -VIRTIO_CRYPTO_INVSESS; + } + + sess = builtin->sessions[op_info->session_id]; + if (algtype == CRYPTODEV_BACKEND_ALG_SYM) { + sym_op_info = op_info->u.sym_op_info; + ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp); + } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) { + asym_op_info = op_info->u.asym_op_info; + ret = cryptodev_builtin_asym_operation(sess, op_info->op_code, + asym_op_info, errp); + } + + return ret; +} + static void cryptodev_builtin_cleanup( CryptoDevBackend *backend, Error **errp) @@ -348,7 +593,7 @@ static void cryptodev_builtin_cleanup( for (i = 0; i < MAX_NUM_SESSIONS; i++) { if (builtin->sessions[i] != NULL) { - cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort); + cryptodev_builtin_close_session(backend, i, 0, &error_abort); } } @@ -370,9 +615,9 @@ cryptodev_builtin_class_init(ObjectClass *oc, void *data) bc->init = cryptodev_builtin_init; bc->cleanup = cryptodev_builtin_cleanup; - bc->create_session = cryptodev_builtin_sym_create_session; - bc->close_session = cryptodev_builtin_sym_close_session; - bc->do_sym_op = cryptodev_builtin_sym_operation; + bc->create_session = cryptodev_builtin_create_session; + bc->close_session = cryptodev_builtin_close_session; + bc->do_op = cryptodev_builtin_operation; } static const TypeInfo cryptodev_builtin_info = { diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index bedb452474..5443a59153 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -259,7 +259,33 @@ static int64_t cryptodev_vhost_user_sym_create_session( return -1; } -static int cryptodev_vhost_user_sym_close_session( +static int64_t cryptodev_vhost_user_create_session( + CryptoDevBackend *backend, + CryptoDevBackendSessionInfo *sess_info, + uint32_t queue_index, Error **errp) +{ + uint32_t op_code = sess_info->op_code; + CryptoDevBackendSymSessionInfo *sym_sess_info; + + switch (op_code) { + case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: + case VIRTIO_CRYPTO_MAC_CREATE_SESSION: + case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: + sym_sess_info = &sess_info->u.sym_sess_info; + return cryptodev_vhost_user_sym_create_session(backend, sym_sess_info, + queue_index, errp); + default: + error_setg(errp, "Unsupported opcode :%" PRIu32 "", + sess_info->op_code); + return -1; + + } + + return -1; +} + +static int cryptodev_vhost_user_close_session( CryptoDevBackend *backend, uint64_t session_id, uint32_t queue_index, Error **errp) @@ -351,9 +377,9 @@ cryptodev_vhost_user_class_init(ObjectClass *oc, void *data) bc->init = cryptodev_vhost_user_init; bc->cleanup = cryptodev_vhost_user_cleanup; - bc->create_session = cryptodev_vhost_user_sym_create_session; - bc->close_session = cryptodev_vhost_user_sym_close_session; - bc->do_sym_op = NULL; + bc->create_session = cryptodev_vhost_user_create_session; + bc->close_session = cryptodev_vhost_user_close_session; + bc->do_op = NULL; object_class_property_add_str(oc, "chardev", cryptodev_vhost_user_get_chardev, diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 2b105e433c..33eb4e1a70 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -72,9 +72,9 @@ void cryptodev_backend_cleanup( } } -int64_t cryptodev_backend_sym_create_session( +int64_t cryptodev_backend_create_session( CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, + CryptoDevBackendSessionInfo *sess_info, uint32_t queue_index, Error **errp) { CryptoDevBackendClass *bc = @@ -87,7 +87,7 @@ int64_t cryptodev_backend_sym_create_session( return -1; } -int cryptodev_backend_sym_close_session( +int cryptodev_backend_close_session( CryptoDevBackend *backend, uint64_t session_id, uint32_t queue_index, Error **errp) @@ -102,16 +102,16 @@ int cryptodev_backend_sym_close_session( return -1; } -static int cryptodev_backend_sym_operation( +static int cryptodev_backend_operation( CryptoDevBackend *backend, - CryptoDevBackendSymOpInfo *op_info, + CryptoDevBackendOpInfo *op_info, uint32_t queue_index, Error **errp) { CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(backend); - if (bc->do_sym_op) { - return bc->do_sym_op(backend, op_info, queue_index, errp); + if (bc->do_op) { + return bc->do_op(backend, op_info, queue_index, errp); } return -VIRTIO_CRYPTO_ERR; @@ -123,20 +123,18 @@ int cryptodev_backend_crypto_operation( uint32_t queue_index, Error **errp) { VirtIOCryptoReq *req = opaque; + CryptoDevBackendOpInfo *op_info = &req->op_info; + enum CryptoDevBackendAlgType algtype = req->flags; - if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { - CryptoDevBackendSymOpInfo *op_info; - op_info = req->u.sym_op_info; - - return cryptodev_backend_sym_operation(backend, - op_info, queue_index, errp); - } else { + if ((algtype != CRYPTODEV_BACKEND_ALG_SYM) + && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) { error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "", - req->flags); - return -VIRTIO_CRYPTO_NOTSUPP; + algtype); + + return -VIRTIO_CRYPTO_NOTSUPP; } - return -VIRTIO_CRYPTO_ERR; + return cryptodev_backend_operation(backend, op_info, queue_index, errp); } static void diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index dcd80b904d..fc1ca90202 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -83,7 +83,8 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, struct iovec *iov, unsigned int out_num) { VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); - CryptoDevBackendSymSessionInfo info; + CryptoDevBackendSessionInfo info; + CryptoDevBackendSymSessionInfo *sym_info; int64_t session_id; int queue_index; uint32_t op_type; @@ -92,11 +93,13 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, memset(&info, 0, sizeof(info)); op_type = ldl_le_p(&sess_req->op_type); - info.op_type = op_type; info.op_code = opcode; + sym_info = &info.u.sym_sess_info; + sym_info->op_type = op_type; + if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { - ret = virtio_crypto_cipher_session_helper(vdev, &info, + ret = virtio_crypto_cipher_session_helper(vdev, sym_info, &sess_req->u.cipher.para, &iov, &out_num); if (ret < 0) { @@ -105,47 +108,47 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { size_t s; /* cipher part */ - ret = virtio_crypto_cipher_session_helper(vdev, &info, + ret = virtio_crypto_cipher_session_helper(vdev, sym_info, &sess_req->u.chain.para.cipher_param, &iov, &out_num); if (ret < 0) { goto err; } /* hash part */ - info.alg_chain_order = ldl_le_p( + sym_info->alg_chain_order = ldl_le_p( &sess_req->u.chain.para.alg_chain_order); - info.add_len = ldl_le_p(&sess_req->u.chain.para.aad_len); - info.hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode); - if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) { - info.hash_alg = ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo); - info.auth_key_len = ldl_le_p( + sym_info->add_len = ldl_le_p(&sess_req->u.chain.para.aad_len); + sym_info->hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode); + if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) { + sym_info->hash_alg = + ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo); + sym_info->auth_key_len = ldl_le_p( &sess_req->u.chain.para.u.mac_param.auth_key_len); - info.hash_result_len = ldl_le_p( + sym_info->hash_result_len = ldl_le_p( &sess_req->u.chain.para.u.mac_param.hash_result_len); - if (info.auth_key_len > vcrypto->conf.max_auth_key_len) { + if (sym_info->auth_key_len > vcrypto->conf.max_auth_key_len) { error_report("virtio-crypto length of auth key is too big: %u", - info.auth_key_len); + sym_info->auth_key_len); ret = -VIRTIO_CRYPTO_ERR; goto err; } /* get auth key */ - if (info.auth_key_len > 0) { - DPRINTF("auth_keylen=%" PRIu32 "\n", info.auth_key_len); - info.auth_key = g_malloc(info.auth_key_len); - s = iov_to_buf(iov, out_num, 0, info.auth_key, - info.auth_key_len); - if (unlikely(s != info.auth_key_len)) { + if (sym_info->auth_key_len > 0) { + sym_info->auth_key = g_malloc(sym_info->auth_key_len); + s = iov_to_buf(iov, out_num, 0, sym_info->auth_key, + sym_info->auth_key_len); + if (unlikely(s != sym_info->auth_key_len)) { virtio_error(vdev, "virtio-crypto authenticated key incorrect"); ret = -EFAULT; goto err; } - iov_discard_front(&iov, &out_num, info.auth_key_len); + iov_discard_front(&iov, &out_num, sym_info->auth_key_len); } - } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) { - info.hash_alg = ldl_le_p( + } else if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) { + sym_info->hash_alg = ldl_le_p( &sess_req->u.chain.para.u.hash_param.algo); - info.hash_result_len = ldl_le_p( + sym_info->hash_result_len = ldl_le_p( &sess_req->u.chain.para.u.hash_param.hash_result_len); } else { /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */ @@ -161,13 +164,10 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, } queue_index = virtio_crypto_vq2q(queue_id); - session_id = cryptodev_backend_sym_create_session( + session_id = cryptodev_backend_create_session( vcrypto->cryptodev, &info, queue_index, &local_err); if (session_id >= 0) { - DPRINTF("create session_id=%" PRIu64 " successfully\n", - session_id); - ret = session_id; } else { if (local_err) { @@ -177,11 +177,82 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, } err: - g_free(info.cipher_key); - g_free(info.auth_key); + g_free(sym_info->cipher_key); + g_free(sym_info->auth_key); return ret; } +static int64_t +virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto, + struct virtio_crypto_akcipher_create_session_req *sess_req, + uint32_t queue_id, uint32_t opcode, + struct iovec *iov, unsigned int out_num) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoDevBackendSessionInfo info = {0}; + CryptoDevBackendAsymSessionInfo *asym_info; + int64_t session_id; + int queue_index; + uint32_t algo, keytype, keylen; + uint8_t *key = NULL; + Error *local_err = NULL; + + algo = ldl_le_p(&sess_req->para.algo); + keytype = ldl_le_p(&sess_req->para.keytype); + keylen = ldl_le_p(&sess_req->para.keylen); + + if ((keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC) + && (keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE)) { + error_report("unsupported asym keytype: %d", keytype); + return -VIRTIO_CRYPTO_NOTSUPP; + } + + if (keylen) { + key = g_malloc(keylen); + if (iov_to_buf(iov, out_num, 0, key, keylen) != keylen) { + virtio_error(vdev, "virtio-crypto asym key incorrect"); + g_free(key); + return -EFAULT; + } + iov_discard_front(&iov, &out_num, keylen); + } + + info.op_code = opcode; + asym_info = &info.u.asym_sess_info; + asym_info->algo = algo; + asym_info->keytype = keytype; + asym_info->keylen = keylen; + asym_info->key = key; + switch (asym_info->algo) { + case VIRTIO_CRYPTO_AKCIPHER_RSA: + asym_info->u.rsa.padding_algo = + ldl_le_p(&sess_req->para.u.rsa.padding_algo); + asym_info->u.rsa.hash_algo = + ldl_le_p(&sess_req->para.u.rsa.hash_algo); + break; + + case VIRTIO_CRYPTO_AKCIPHER_ECDSA: + asym_info->u.ecdsa.curve_id = + ldl_le_p(&sess_req->para.u.ecdsa.curve_id); + break; + + default: + return -VIRTIO_CRYPTO_ERR; + } + + queue_index = virtio_crypto_vq2q(queue_id); + session_id = cryptodev_backend_create_session(vcrypto->cryptodev, &info, + queue_index, &local_err); + if (session_id < 0) { + if (local_err) { + error_report_err(local_err); + } + return -VIRTIO_CRYPTO_ERR; + } + + return session_id; +} + static uint8_t virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto, struct virtio_crypto_destroy_session_req *close_sess_req, @@ -193,9 +264,8 @@ virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto, Error *local_err = NULL; session_id = ldq_le_p(&close_sess_req->session_id); - DPRINTF("close session, id=%" PRIu64 "\n", session_id); - ret = cryptodev_backend_sym_close_session( + ret = cryptodev_backend_close_session( vcrypto->cryptodev, session_id, queue_id, &local_err); if (ret == 0) { status = VIRTIO_CRYPTO_OK; @@ -260,13 +330,22 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) opcode = ldl_le_p(&ctrl.header.opcode); queue_id = ldl_le_p(&ctrl.header.queue_id); + memset(&input, 0, sizeof(input)); switch (opcode) { case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: - memset(&input, 0, sizeof(input)); session_id = virtio_crypto_create_sym_session(vcrypto, &ctrl.u.sym_create_session, queue_id, opcode, out_iov, out_num); + goto check_session; + + case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION: + session_id = virtio_crypto_create_asym_session(vcrypto, + &ctrl.u.akcipher_create_session, + queue_id, opcode, + out_iov, out_num); + +check_session: /* Serious errors, need to reset virtio crypto device */ if (session_id == -EFAULT) { virtqueue_detach_element(vq, elem, 0); @@ -290,10 +369,12 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) virtqueue_push(vq, elem, sizeof(input)); virtio_notify(vdev, vq); break; + case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION: case VIRTIO_CRYPTO_HASH_DESTROY_SESSION: case VIRTIO_CRYPTO_MAC_DESTROY_SESSION: case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION: + case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION: status = virtio_crypto_handle_close_session(vcrypto, &ctrl.u.destroy_session, queue_id); /* The status only occupy one byte, we can directly use it */ @@ -311,7 +392,6 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: default: error_report("virtio-crypto unsupported ctrl opcode: %d", opcode); - memset(&input, 0, sizeof(input)); stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP); s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input)); if (unlikely(s != sizeof(input))) { @@ -339,28 +419,37 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq, req->in_num = 0; req->in_len = 0; req->flags = CRYPTODEV_BACKEND_ALG__MAX; - req->u.sym_op_info = NULL; + memset(&req->op_info, 0x00, sizeof(req->op_info)); } static void virtio_crypto_free_request(VirtIOCryptoReq *req) { - if (req) { - if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { - size_t max_len; - CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info; - - max_len = op_info->iv_len + - op_info->aad_len + - op_info->src_len + - op_info->dst_len + - op_info->digest_result_len; - - /* Zeroize and free request data structure */ - memset(op_info, 0, sizeof(*op_info) + max_len); + if (!req) { + return; + } + + if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { + size_t max_len; + CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info; + + max_len = op_info->iv_len + + op_info->aad_len + + op_info->src_len + + op_info->dst_len + + op_info->digest_result_len; + + /* Zeroize and free request data structure */ + memset(op_info, 0, sizeof(*op_info) + max_len); + g_free(op_info); + } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) { + CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info; + if (op_info) { + memset(op_info, 0, sizeof(*op_info)); g_free(op_info); } - g_free(req); } + + g_free(req); } static void @@ -397,6 +486,35 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev, } } +static void +virtio_crypto_akcipher_input_data_helper(VirtIODevice *vdev, + VirtIOCryptoReq *req, int32_t status, + CryptoDevBackendAsymOpInfo *asym_op_info) +{ + size_t s, len; + + if (status != VIRTIO_CRYPTO_OK) { + return; + } + + len = asym_op_info->dst_len; + if (!len) { + return; + } + + s = iov_from_buf(req->in_iov, req->in_num, 0, asym_op_info->dst, len); + if (s != len) { + virtio_error(vdev, "virtio-crypto asym dest data incorrect"); + return; + } + + iov_discard_front(&req->in_iov, &req->in_num, len); + + /* For akcipher, dst_len may be changed after operation */ + req->in_len = sizeof(struct virtio_crypto_inhdr) + asym_op_info->dst_len; +} + + static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status) { VirtIOCrypto *vcrypto = req->vcrypto; @@ -404,7 +522,10 @@ static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status) if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) { virtio_crypto_sym_input_data_helper(vdev, req, status, - req->u.sym_op_info); + req->op_info.u.sym_op_info); + } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) { + virtio_crypto_akcipher_input_data_helper(vdev, req, status, + req->op_info.u.asym_op_info); } stb_p(&req->in->status, status); virtqueue_push(req->vq, &req->elem, req->in_len); @@ -543,41 +664,100 @@ err: static int virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto, struct virtio_crypto_sym_data_req *req, - CryptoDevBackendSymOpInfo **sym_op_info, + CryptoDevBackendOpInfo *op_info, struct iovec *iov, unsigned int out_num) { VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoDevBackendSymOpInfo *sym_op_info; uint32_t op_type; - CryptoDevBackendSymOpInfo *op_info; op_type = ldl_le_p(&req->op_type); - if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { - op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para, + sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para, NULL, iov, out_num); - if (!op_info) { + if (!sym_op_info) { return -EFAULT; } - op_info->op_type = op_type; } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { - op_info = virtio_crypto_sym_op_helper(vdev, NULL, + sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL, &req->u.chain.para, iov, out_num); - if (!op_info) { + if (!sym_op_info) { return -EFAULT; } - op_info->op_type = op_type; } else { /* VIRTIO_CRYPTO_SYM_OP_NONE */ error_report("virtio-crypto unsupported cipher type"); return -VIRTIO_CRYPTO_NOTSUPP; } - *sym_op_info = op_info; + sym_op_info->op_type = op_type; + op_info->u.sym_op_info = sym_op_info; return 0; } +static int +virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto, + struct virtio_crypto_akcipher_data_req *req, + CryptoDevBackendOpInfo *op_info, + struct iovec *iov, unsigned int out_num) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoDevBackendAsymOpInfo *asym_op_info; + uint32_t src_len; + uint32_t dst_len; + uint32_t len; + uint8_t *src = NULL; + uint8_t *dst = NULL; + + asym_op_info = g_malloc0(sizeof(CryptoDevBackendAsymOpInfo)); + src_len = ldl_le_p(&req->para.src_data_len); + dst_len = ldl_le_p(&req->para.dst_data_len); + + if (src_len > 0) { + src = g_malloc0(src_len); + len = iov_to_buf(iov, out_num, 0, src, src_len); + if (unlikely(len != src_len)) { + virtio_error(vdev, "virtio-crypto asym src data incorrect" + "expected %u, actual %u", src_len, len); + goto err; + } + + iov_discard_front(&iov, &out_num, src_len); + } + + if (dst_len > 0) { + dst = g_malloc0(dst_len); + + if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) { + len = iov_to_buf(iov, out_num, 0, dst, dst_len); + if (unlikely(len != dst_len)) { + virtio_error(vdev, "virtio-crypto asym dst data incorrect" + "expected %u, actual %u", dst_len, len); + goto err; + } + + iov_discard_front(&iov, &out_num, dst_len); + } + } + + asym_op_info->src_len = src_len; + asym_op_info->dst_len = dst_len; + asym_op_info->src = src; + asym_op_info->dst = dst; + op_info->u.asym_op_info = asym_op_info; + + return 0; + + err: + g_free(asym_op_info); + g_free(src); + g_free(dst); + + return -EFAULT; +} + static int virtio_crypto_handle_request(VirtIOCryptoReq *request) { @@ -595,8 +775,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) unsigned out_num; uint32_t opcode; uint8_t status = VIRTIO_CRYPTO_ERR; - uint64_t session_id; - CryptoDevBackendSymOpInfo *sym_op_info = NULL; + CryptoDevBackendOpInfo *op_info = &request->op_info; Error *local_err = NULL; if (elem->out_num < 1 || elem->in_num < 1) { @@ -639,15 +818,28 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) request->in_iov = in_iov; opcode = ldl_le_p(&req.header.opcode); - session_id = ldq_le_p(&req.header.session_id); + op_info->session_id = ldq_le_p(&req.header.session_id); + op_info->op_code = opcode; switch (opcode) { case VIRTIO_CRYPTO_CIPHER_ENCRYPT: case VIRTIO_CRYPTO_CIPHER_DECRYPT: + op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_SYM; ret = virtio_crypto_handle_sym_req(vcrypto, - &req.u.sym_req, - &sym_op_info, + &req.u.sym_req, op_info, + out_iov, out_num); + goto check_result; + + case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT: + case VIRTIO_CRYPTO_AKCIPHER_DECRYPT: + case VIRTIO_CRYPTO_AKCIPHER_SIGN: + case VIRTIO_CRYPTO_AKCIPHER_VERIFY: + op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_ASYM; + ret = virtio_crypto_handle_asym_req(vcrypto, + &req.u.akcipher_req, op_info, out_iov, out_num); + +check_result: /* Serious errors, need to reset virtio crypto device */ if (ret == -EFAULT) { return -1; @@ -655,11 +847,8 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP); virtio_crypto_free_request(request); } else { - sym_op_info->session_id = session_id; /* Set request's parameter */ - request->flags = CRYPTODEV_BACKEND_ALG_SYM; - request->u.sym_op_info = sym_op_info; ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev, request, queue_index, &local_err); if (ret < 0) { @@ -674,6 +863,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request) virtio_crypto_free_request(request); } break; + case VIRTIO_CRYPTO_HASH: case VIRTIO_CRYPTO_MAC: case VIRTIO_CRYPTO_AEAD_ENCRYPT: @@ -779,6 +969,7 @@ static void virtio_crypto_init_config(VirtIODevice *vdev) vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l; vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h; vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo; + vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo; vcrypto->conf.max_cipher_key_len = vcrypto->conf.cryptodev->conf.max_cipher_key_len; vcrypto->conf.max_auth_key_len = @@ -891,6 +1082,7 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config) stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len); stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len); stq_le_p(&crypto_cfg.max_size, c->conf.max_size); + stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo); memcpy(config, &crypto_cfg, c->config_size); } diff --git a/include/hw/virtio/virtio-crypto.h b/include/hw/virtio/virtio-crypto.h index a2228d7b2e..348749f5d5 100644 --- a/include/hw/virtio/virtio-crypto.h +++ b/include/hw/virtio/virtio-crypto.h @@ -50,6 +50,7 @@ typedef struct VirtIOCryptoConf { uint32_t mac_algo_l; uint32_t mac_algo_h; uint32_t aead_algo; + uint32_t akcipher_algo; /* Maximum length of cipher key */ uint32_t max_cipher_key_len; @@ -71,9 +72,7 @@ typedef struct VirtIOCryptoReq { size_t in_len; VirtQueue *vq; struct VirtIOCrypto *vcrypto; - union { - CryptoDevBackendSymOpInfo *sym_op_info; - } u; + CryptoDevBackendOpInfo op_info; } VirtIOCryptoReq; typedef struct VirtIOCryptoQueue { diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h index f4d4057d4d..b306775849 100644 --- a/include/sysemu/cryptodev.h +++ b/include/sysemu/cryptodev.h @@ -50,13 +50,13 @@ typedef struct CryptoDevBackendClient enum CryptoDevBackendAlgType { CRYPTODEV_BACKEND_ALG_SYM, + CRYPTODEV_BACKEND_ALG_ASYM, CRYPTODEV_BACKEND_ALG__MAX, }; /** * CryptoDevBackendSymSessionInfo: * - * @op_code: operation code (refer to virtio_crypto.h) * @cipher_alg: algorithm type of CIPHER * @key_len: byte length of cipher key * @hash_alg: algorithm type of HASH/MAC @@ -74,7 +74,6 @@ enum CryptoDevBackendAlgType { */ typedef struct CryptoDevBackendSymSessionInfo { /* corresponding with virtio crypto spec */ - uint32_t op_code; uint32_t cipher_alg; uint32_t key_len; uint32_t hash_alg; @@ -89,11 +88,41 @@ typedef struct CryptoDevBackendSymSessionInfo { uint8_t *auth_key; } CryptoDevBackendSymSessionInfo; +/** + * CryptoDevBackendAsymSessionInfo: + */ +typedef struct CryptoDevBackendRsaPara { + uint32_t padding_algo; + uint32_t hash_algo; +} CryptoDevBackendRsaPara; + +typedef struct CryptoDevBackendEcdsaPara { + uint32_t curve_id; +} CryptoDevBackendEcdsaPara; + +typedef struct CryptoDevBackendAsymSessionInfo { + /* corresponding with virtio crypto spec */ + uint32_t algo; + uint32_t keytype; + uint32_t keylen; + uint8_t *key; + union { + CryptoDevBackendRsaPara rsa; + CryptoDevBackendEcdsaPara ecdsa; + } u; +} CryptoDevBackendAsymSessionInfo; + +typedef struct CryptoDevBackendSessionInfo { + uint32_t op_code; + union { + CryptoDevBackendSymSessionInfo sym_sess_info; + CryptoDevBackendAsymSessionInfo asym_sess_info; + } u; +} CryptoDevBackendSessionInfo; + /** * CryptoDevBackendSymOpInfo: * - * @session_id: session index which was previously - * created by cryptodev_backend_sym_create_session() * @aad_len: byte length of additional authenticated data * @iv_len: byte length of initialization vector or counter * @src_len: byte length of source data @@ -119,7 +148,6 @@ typedef struct CryptoDevBackendSymSessionInfo { * */ typedef struct CryptoDevBackendSymOpInfo { - uint64_t session_id; uint32_t aad_len; uint32_t iv_len; uint32_t src_len; @@ -138,6 +166,33 @@ typedef struct CryptoDevBackendSymOpInfo { uint8_t data[]; } CryptoDevBackendSymOpInfo; + +/** + * CryptoDevBackendAsymOpInfo: + * + * @src_len: byte length of source data + * @dst_len: byte length of destination data + * @src: point to the source data + * @dst: point to the destination data + * + */ +typedef struct CryptoDevBackendAsymOpInfo { + uint32_t src_len; + uint32_t dst_len; + uint8_t *src; + uint8_t *dst; +} CryptoDevBackendAsymOpInfo; + +typedef struct CryptoDevBackendOpInfo { + enum CryptoDevBackendAlgType algtype; + uint32_t op_code; + uint64_t session_id; + union { + CryptoDevBackendSymOpInfo *sym_op_info; + CryptoDevBackendAsymOpInfo *asym_op_info; + } u; +} CryptoDevBackendOpInfo; + struct CryptoDevBackendClass { ObjectClass parent_class; @@ -145,13 +200,13 @@ struct CryptoDevBackendClass { void (*cleanup)(CryptoDevBackend *backend, Error **errp); int64_t (*create_session)(CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, + CryptoDevBackendSessionInfo *sess_info, uint32_t queue_index, Error **errp); int (*close_session)(CryptoDevBackend *backend, uint64_t session_id, uint32_t queue_index, Error **errp); - int (*do_sym_op)(CryptoDevBackend *backend, - CryptoDevBackendSymOpInfo *op_info, + int (*do_op)(CryptoDevBackend *backend, + CryptoDevBackendOpInfo *op_info, uint32_t queue_index, Error **errp); }; @@ -190,6 +245,7 @@ struct CryptoDevBackendConf { uint32_t mac_algo_l; uint32_t mac_algo_h; uint32_t aead_algo; + uint32_t akcipher_algo; /* Maximum length of cipher key */ uint32_t max_cipher_key_len; /* Maximum length of authenticated key */ @@ -247,34 +303,34 @@ void cryptodev_backend_cleanup( Error **errp); /** - * cryptodev_backend_sym_create_session: + * cryptodev_backend_create_session: * @backend: the cryptodev backend object * @sess_info: parameters needed by session creating * @queue_index: queue index of cryptodev backend client * @errp: pointer to a NULL-initialized error object * - * Create a session for symmetric algorithms + * Create a session for symmetric/symmetric algorithms * * Returns: session id on success, or -1 on error */ -int64_t cryptodev_backend_sym_create_session( +int64_t cryptodev_backend_create_session( CryptoDevBackend *backend, - CryptoDevBackendSymSessionInfo *sess_info, + CryptoDevBackendSessionInfo *sess_info, uint32_t queue_index, Error **errp); /** - * cryptodev_backend_sym_close_session: + * cryptodev_backend_close_session: * @backend: the cryptodev backend object * @session_id: the session id * @queue_index: queue index of cryptodev backend client * @errp: pointer to a NULL-initialized error object * - * Close a session for symmetric algorithms which was previously - * created by cryptodev_backend_sym_create_session() + * Close a session for which was previously + * created by cryptodev_backend_create_session() * * Returns: 0 on success, or Negative on error */ -int cryptodev_backend_sym_close_session( +int cryptodev_backend_close_session( CryptoDevBackend *backend, uint64_t session_id, uint32_t queue_index, Error **errp);