From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8EC93A0093; Tue, 14 Jun 2022 15:26:13 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6C50F42B78; Tue, 14 Jun 2022 15:25:53 +0200 (CEST) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mails.dpdk.org (Postfix) with ESMTP id BA4B142836 for ; Tue, 14 Jun 2022 15:25:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1655213151; x=1686749151; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=O/WG93iJJpIia5CAWRic5ofIyNzgsd3DQUqDvNFemW4=; b=DkyPFfSQNFjXqLDDV1I1yC9dnnh+na9KBe5W+SVzv7DXSz1zJyk5UtWt 62LTynDTkNOkObQ7uuKFv1DIKdMteNsYXWB+2WeQF3zZUkUBoflrIVs1a IIqAfq7jLqxiBLQPat9QnwQweZDtEWyOGnpIOlvIGrGRmLkY0bYJV9KSF tUEXoMAZSUfxeBHctn0zAKFGGpvJN/XV3eB4KXcnTH6590rMR2j9H+E2b uH9JatF4g4301h5jlB4Lx5o7dJdiQTMbtBmFJs0xhu8/swe4wFYu4r16J NG/Kg1WF4pqaVizcpD2hBFH/j1/dP/5NOKMqzJYx+8s/6Y8EMIUi4rRiZ g==; X-IronPort-AV: E=McAfee;i="6400,9594,10377"; a="279653272" X-IronPort-AV: E=Sophos;i="5.91,300,1647327600"; d="scan'208";a="279653272" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Jun 2022 06:25:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,300,1647327600"; d="scan'208";a="569974231" Received: from silpixa00400465.ir.intel.com ([10.55.128.22]) by orsmga002.jf.intel.com with ESMTP; 14 Jun 2022 06:25:50 -0700 From: Kai Ji To: dev@dpdk.org Cc: gakhil@marvell.com, Kai Ji Subject: [dpdk-dev v4 4/4] crypto/openssl: 3.0 EVP update on DSA routine Date: Tue, 14 Jun 2022 21:25:42 +0800 Message-Id: <20220614132542.76241-5-kai.ji@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220614132542.76241-1-kai.ji@intel.com> References: <20220613164023.70872-1-kai.ji@intel.com> <20220614132542.76241-1-kai.ji@intel.com> X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch updates asymmetric DSA routine in crypto openssl pmd to adopt openssl 3.0 EVP apis. Divide the single combined dsa sign test to two individual dsa sign and dsa verfiy tests. Signed-off-by: Kai Ji --- app/test/test_cryptodev_asym.c | 90 ++++++++-- drivers/crypto/openssl/compat.h | 12 ++ drivers/crypto/openssl/openssl_pmd_private.h | 3 + drivers/crypto/openssl/rte_openssl_pmd.c | 177 ++++++++++++++++++- drivers/crypto/openssl/rte_openssl_pmd_ops.c | 72 +++++++- 5 files changed, 330 insertions(+), 24 deletions(-) diff --git a/app/test/test_cryptodev_asym.c b/app/test/test_cryptodev_asym.c index 7bd7cde16e..c9c48d1e87 100644 --- a/app/test/test_cryptodev_asym.c +++ b/app/test/test_cryptodev_asym.c @@ -1642,7 +1642,7 @@ test_dh_keygenration(void) } static int -test_dsa_sign(void) +test_dsa_sign(struct rte_crypto_dsa_op_param *dsa_op) { struct crypto_testsuite_params_asym *ts_params = &testsuite_params; struct rte_mempool *op_mpool = ts_params->op_mpool; @@ -1652,9 +1652,6 @@ test_dsa_sign(void) struct rte_crypto_op *op = NULL, *result_op = NULL; void *sess = NULL; int status = TEST_SUCCESS; - uint8_t r[TEST_DH_MOD_LEN]; - uint8_t s[TEST_DH_MOD_LEN]; - uint8_t dgst[] = "35d81554afaad2cf18f3a1770d5fedc4ea5be344"; int ret; ret = rte_cryptodev_asym_session_create(dev_id, &dsa_xform, sess_mpool, &sess); @@ -1676,6 +1673,7 @@ test_dsa_sign(void) goto error_exit; } asym_op = op->asym; + asym_op->dsa = *dsa_op; debug_hexdump(stdout, "p: ", dsa_xform.dsa.p.data, dsa_xform.dsa.p.length); @@ -1689,13 +1687,6 @@ test_dsa_sign(void) /* attach asymmetric crypto session to crypto operations */ rte_crypto_op_attach_asym_session(op, sess); asym_op->dsa.op_type = RTE_CRYPTO_ASYM_OP_SIGN; - asym_op->dsa.message.data = dgst; - asym_op->dsa.message.length = sizeof(dgst); - asym_op->dsa.r.length = sizeof(r); - asym_op->dsa.r.data = r; - asym_op->dsa.s.length = sizeof(s); - asym_op->dsa.s.data = s; - RTE_LOG(DEBUG, USER1, "Process ASYM operation"); /* Process crypto operation */ @@ -1719,12 +1710,71 @@ test_dsa_sign(void) } asym_op = result_op->asym; + dsa_op->r.length = asym_op->dsa.r.length; + dsa_op->s.length = asym_op->dsa.s.length; debug_hexdump(stdout, "r:", asym_op->dsa.r.data, asym_op->dsa.r.length); debug_hexdump(stdout, "s:", asym_op->dsa.s.data, asym_op->dsa.s.length); +error_exit: + if (sess != NULL) + rte_cryptodev_asym_session_free(dev_id, sess); + if (op != NULL) + rte_crypto_op_free(op); + return status; +} + +static int +test_dsa_verify(struct rte_crypto_dsa_op_param *dsa_op) +{ + struct crypto_testsuite_params_asym *ts_params = &testsuite_params; + struct rte_mempool *op_mpool = ts_params->op_mpool; + struct rte_mempool *sess_mpool = ts_params->session_mpool; + uint8_t dev_id = ts_params->valid_devs[0]; + struct rte_crypto_asym_op *asym_op = NULL; + struct rte_crypto_op *op = NULL, *result_op = NULL; + void *sess = NULL; + int status = TEST_SUCCESS; + int ret; + ret = rte_cryptodev_asym_session_create(dev_id, &dsa_xform, sess_mpool, &sess); + if (ret < 0) { + RTE_LOG(ERR, USER1, + "line %u FAILED: %s", __LINE__, + "Session creation failed"); + status = (ret == -ENOTSUP) ? TEST_SKIPPED : TEST_FAILED; + goto error_exit; + } + /* set up crypto op data structure */ + op = rte_crypto_op_alloc(op_mpool, RTE_CRYPTO_OP_TYPE_ASYMMETRIC); + if (!op) { + RTE_LOG(ERR, USER1, + "line %u FAILED: %s", + __LINE__, "Failed to allocate asymmetric crypto " + "operation struct"); + status = TEST_FAILED; + goto error_exit; + } + asym_op = op->asym; + asym_op->dsa = *dsa_op; + + debug_hexdump(stdout, "p: ", dsa_xform.dsa.p.data, + dsa_xform.dsa.p.length); + debug_hexdump(stdout, "q: ", dsa_xform.dsa.q.data, + dsa_xform.dsa.q.length); + debug_hexdump(stdout, "g: ", dsa_xform.dsa.g.data, + dsa_xform.dsa.g.length); + + /* attach asymmetric crypto session to crypto operations */ + rte_crypto_op_attach_asym_session(op, sess); + + debug_hexdump(stdout, "r:", + asym_op->dsa.r.data, asym_op->dsa.r.length); + debug_hexdump(stdout, "s:", + asym_op->dsa.s.data, asym_op->dsa.s.length); + + RTE_LOG(DEBUG, USER1, "Process ASYM verify operation"); /* Test PMD DSA sign verification using signer public key */ asym_op->dsa.op_type = RTE_CRYPTO_ASYM_OP_VERIFY; @@ -1770,8 +1820,22 @@ static int test_dsa(void) { int status; - status = test_dsa_sign(); - TEST_ASSERT_EQUAL(status, 0, "Test failed"); + uint8_t r[TEST_DH_MOD_LEN]; + uint8_t s[TEST_DH_MOD_LEN]; + struct rte_crypto_dsa_op_param dsa_op; + uint8_t dgst[] = "35d81554afaad2cf18f3a1770d5fedc4ea5be344"; + + dsa_op.message.data = dgst; + dsa_op.message.length = sizeof(dgst); + dsa_op.r.data = r; + dsa_op.s.data = s; + dsa_op.r.length = sizeof(r); + dsa_op.s.length = sizeof(s); + + status = test_dsa_sign(&dsa_op); + TEST_ASSERT_EQUAL(status, 0, "DSA sign test failed"); + status = test_dsa_verify(&dsa_op); + TEST_ASSERT_EQUAL(status, 0, "DSA verify test failed"); return status; } diff --git a/drivers/crypto/openssl/compat.h b/drivers/crypto/openssl/compat.h index eecb7d3698..9f9167c4f1 100644 --- a/drivers/crypto/openssl/compat.h +++ b/drivers/crypto/openssl/compat.h @@ -104,6 +104,18 @@ get_dsa_priv_key(DSA *dsa, BIGNUM **priv_key) *priv_key = dsa->priv_key; } +#elif (OPENSSL_VERSION_NUMBER >= 0x30000000L) +static __rte_always_inline void +set_dsa_sign(DSA_SIG *sign, BIGNUM *r, BIGNUM *s) +{ + DSA_SIG_set0(sign, r, s); +} + +static __rte_always_inline void +get_dsa_sign(DSA_SIG *sign, const BIGNUM **r, const BIGNUM **s) +{ + DSA_SIG_get0(sign, r, s); +} #else static __rte_always_inline int diff --git a/drivers/crypto/openssl/openssl_pmd_private.h b/drivers/crypto/openssl/openssl_pmd_private.h index 8fdbc75511..b0e5cd109b 100644 --- a/drivers/crypto/openssl/openssl_pmd_private.h +++ b/drivers/crypto/openssl/openssl_pmd_private.h @@ -184,6 +184,9 @@ struct openssl_asym_session { } dh; struct { DSA *dsa; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + OSSL_PARAM_BLD * param_bld; +#endif } s; } u; } __rte_cache_aligned; diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c index cbc525a021..900b393fa9 100644 --- a/drivers/crypto/openssl/rte_openssl_pmd.c +++ b/drivers/crypto/openssl/rte_openssl_pmd.c @@ -2,8 +2,6 @@ * Copyright(c) 2016-2017 Intel Corporation */ -#define OPENSSL_API_COMPAT 0x10100000L - #include #include #include @@ -1764,6 +1762,171 @@ process_openssl_auth_op(struct openssl_qp *qp, struct rte_crypto_op *op, } /* process dsa sign operation */ +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +static int +process_openssl_dsa_sign_op_evp(struct rte_crypto_op *cop, + struct openssl_asym_session *sess) +{ + struct rte_crypto_dsa_op_param *op = &cop->asym->dsa; + EVP_PKEY_CTX *dsa_ctx = NULL; + EVP_PKEY_CTX *key_ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL); + EVP_PKEY *pkey = NULL; + OSSL_PARAM_BLD *param_bld = sess->u.s.param_bld; + OSSL_PARAM *params = NULL; + + size_t outlen; + unsigned char *dsa_sign_data; + const unsigned char *dsa_sign_data_p; + + cop->status = RTE_CRYPTO_OP_STATUS_ERROR; + params = OSSL_PARAM_BLD_to_param(param_bld); + if (!params) { + OSSL_PARAM_BLD_free(param_bld); + return -1; + } + + if (key_ctx == NULL + || EVP_PKEY_fromdata_init(key_ctx) <= 0 + || EVP_PKEY_fromdata(key_ctx, &pkey, + EVP_PKEY_PUBLIC_KEY, params) <= 0) + goto err_dsa_sign; + + dsa_ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!dsa_ctx) + goto err_dsa_sign; + + if (EVP_PKEY_sign_init(dsa_ctx) <= 0) + goto err_dsa_sign; + + if (EVP_PKEY_sign(dsa_ctx, NULL, &outlen, op->message.data, + op->message.length) <= 0) + goto err_dsa_sign; + + if (outlen <= 0) + goto err_dsa_sign; + + dsa_sign_data = OPENSSL_malloc(outlen); + if (!dsa_sign_data) + goto err_dsa_sign; + + if (EVP_PKEY_sign(dsa_ctx, dsa_sign_data, &outlen, op->message.data, + op->message.length) <= 0) { + free(dsa_sign_data); + goto err_dsa_sign; + } + + dsa_sign_data_p = (const unsigned char *)dsa_sign_data; + DSA_SIG *sign = d2i_DSA_SIG(NULL, &dsa_sign_data_p, outlen); + if (!sign) { + OPENSSL_LOG(ERR, "%s:%d\n", __func__, __LINE__); + free(dsa_sign_data); + goto err_dsa_sign; + } else { + const BIGNUM *r = NULL, *s = NULL; + get_dsa_sign(sign, &r, &s); + + op->r.length = BN_bn2bin(r, op->r.data); + op->s.length = BN_bn2bin(s, op->s.data); + cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS; + } + + DSA_SIG_free(sign); + free(dsa_sign_data); + return 0; + +err_dsa_sign: + if (params) + OSSL_PARAM_free(params); + if (key_ctx) + EVP_PKEY_CTX_free(key_ctx); + if (dsa_ctx) + EVP_PKEY_CTX_free(dsa_ctx); + return -1; +} + +/* process dsa verify operation */ +static int +process_openssl_dsa_verify_op_evp(struct rte_crypto_op *cop, + struct openssl_asym_session *sess) +{ + struct rte_crypto_dsa_op_param *op = &cop->asym->dsa; + DSA_SIG *sign = DSA_SIG_new(); + BIGNUM *r = NULL, *s = NULL; + BIGNUM *pub_key = NULL; + OSSL_PARAM_BLD *param_bld = sess->u.s.param_bld; + OSSL_PARAM *params = NULL; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *dsa_ctx = NULL; + EVP_PKEY_CTX *key_ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL); + unsigned char *dsa_sig = NULL; + size_t sig_len; + int ret = -1; + + cop->status = RTE_CRYPTO_OP_STATUS_ERROR; + if (!param_bld) { + OPENSSL_LOG(ERR, " %s:%d\n", __func__, __LINE__); + return -1; + } + + r = BN_bin2bn(op->r.data, op->r.length, r); + s = BN_bin2bn(op->s.data, op->s.length, s); + pub_key = BN_bin2bn(op->y.data, op->y.length, pub_key); + if (!r || !s || !pub_key) { + BN_free(r); + BN_free(s); + BN_free(pub_key); + OSSL_PARAM_BLD_free(param_bld); + goto err_dsa_verify; + } + + set_dsa_sign(sign, r, s); + if (!OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key)) { + OSSL_PARAM_BLD_free(param_bld); + goto err_dsa_verify; + } + + params = OSSL_PARAM_BLD_to_param(param_bld); + if (!params) { + OSSL_PARAM_BLD_free(param_bld); + goto err_dsa_verify; + } + + if (key_ctx == NULL + || EVP_PKEY_fromdata_init(key_ctx) <= 0 + || EVP_PKEY_fromdata(key_ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) + goto err_dsa_verify; + + dsa_ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!dsa_ctx) + goto err_dsa_verify; + + if (!sign) + goto err_dsa_verify; + + sig_len = i2d_DSA_SIG(sign, &dsa_sig); + if (EVP_PKEY_verify_init(dsa_ctx) <= 0) + goto err_dsa_verify; + + ret = EVP_PKEY_verify(dsa_ctx, dsa_sig, sig_len, + op->message.data, op->message.length); + if (ret == 1) { + cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS; + ret = 0; + } + +err_dsa_verify: + if (sign) + DSA_SIG_free(sign); + if (params) + OSSL_PARAM_free(params); + if (key_ctx) + EVP_PKEY_CTX_free(key_ctx); + if (dsa_ctx) + EVP_PKEY_CTX_free(dsa_ctx); + + return ret; +} +#else static int process_openssl_dsa_sign_op(struct rte_crypto_op *cop, struct openssl_asym_session *sess) @@ -1845,6 +2008,7 @@ process_openssl_dsa_verify_op(struct rte_crypto_op *cop, return 0; } +#endif /* process dh operation */ #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) @@ -2501,6 +2665,14 @@ process_asym_op(struct openssl_qp *qp, struct rte_crypto_op *op, #endif break; case RTE_CRYPTO_ASYM_XFORM_DSA: +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if (op->asym->dsa.op_type == RTE_CRYPTO_ASYM_OP_SIGN) + retval = process_openssl_dsa_sign_op_evp(op, sess); + else if (op->asym->dsa.op_type == + RTE_CRYPTO_ASYM_OP_VERIFY) + retval = + process_openssl_dsa_verify_op_evp(op, sess); +#else if (op->asym->dsa.op_type == RTE_CRYPTO_ASYM_OP_SIGN) retval = process_openssl_dsa_sign_op(op, sess); else if (op->asym->dsa.op_type == @@ -2509,6 +2681,7 @@ process_asym_op(struct openssl_qp *qp, struct rte_crypto_op *op, process_openssl_dsa_verify_op(op, sess); else op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS; +#endif break; default: op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS; diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c index a1a42ef444..59eb80fc72 100644 --- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c +++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c @@ -812,13 +812,13 @@ static int openssl_set_asym_session_parameters( struct openssl_asym_session *asym_session, struct rte_crypto_asym_xform *xform) { - int ret = 0; + int ret = -1; if ((xform->xform_type != RTE_CRYPTO_ASYM_XFORM_DH) && (xform->next != NULL)) { OPENSSL_LOG(ERR, "chained xfrms are not supported on %s", rte_crypto_asym_xform_strings[xform->xform_type]); - return -1; + return ret; } switch (xform->xform_type) { @@ -1003,7 +1003,7 @@ static int openssl_set_asym_session_parameters( if (ret) { OPENSSL_LOG(ERR, "Failed to load rsa keys\n"); RSA_free(rsa); - return -1; + return ret; } asym_session->u.r.rsa = rsa; asym_session->xfrm_type = RTE_CRYPTO_ASYM_XFORM_RSA; @@ -1029,7 +1029,7 @@ static int openssl_set_asym_session_parameters( if (ctx == NULL) { OPENSSL_LOG(ERR, " failed to allocate resources\n"); - return -1; + return ret; } BN_CTX_start(ctx); BIGNUM *mod = BN_CTX_get(ctx); @@ -1037,7 +1037,7 @@ static int openssl_set_asym_session_parameters( if (mod == NULL || exp == NULL) { BN_CTX_end(ctx); BN_CTX_free(ctx); - return -1; + return ret; } mod = BN_bin2bn((const unsigned char *) @@ -1060,14 +1060,14 @@ static int openssl_set_asym_session_parameters( if (ctx == NULL) { OPENSSL_LOG(ERR, " failed to allocate resources\n"); - return -1; + return ret; } BN_CTX_start(ctx); BIGNUM *mod = BN_CTX_get(ctx); if (mod == NULL) { BN_CTX_end(ctx); BN_CTX_free(ctx); - return -1; + return ret; } mod = BN_bin2bn((const unsigned char *) @@ -1158,6 +1158,56 @@ static int openssl_set_asym_session_parameters( } case RTE_CRYPTO_ASYM_XFORM_DSA: { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + BIGNUM *p = NULL, *g = NULL; + BIGNUM *q = NULL, *priv_key = NULL; + BIGNUM *pub_key = BN_new(); + BN_zero(pub_key); + OSSL_PARAM_BLD *param_bld = NULL; + + p = BN_bin2bn((const unsigned char *) + xform->dsa.p.data, + xform->dsa.p.length, + p); + + g = BN_bin2bn((const unsigned char *) + xform->dsa.g.data, + xform->dsa.g.length, + g); + + q = BN_bin2bn((const unsigned char *) + xform->dsa.q.data, + xform->dsa.q.length, + q); + if (!p || !q || !g) + goto err_dsa; + + priv_key = BN_bin2bn((const unsigned char *) + xform->dsa.x.data, + xform->dsa.x.length, + priv_key); + if (priv_key == NULL) + goto err_dsa; + + param_bld = OSSL_PARAM_BLD_new(); + if (!param_bld) { + OPENSSL_LOG(ERR, "failed to allocate resources\n"); + goto err_dsa; + } + + if (!OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) + || !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) + || !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) + || !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key)) { + OSSL_PARAM_BLD_free(param_bld); + OPENSSL_LOG(ERR, "failed to allocate resources\n"); + goto err_dsa; + } + asym_session->xfrm_type = RTE_CRYPTO_ASYM_XFORM_DSA; + asym_session->u.s.param_bld = param_bld; + + break; +#else BIGNUM *p = NULL, *g = NULL; BIGNUM *q = NULL, *priv_key = NULL; BIGNUM *pub_key = BN_new(); @@ -1217,7 +1267,7 @@ static int openssl_set_asym_session_parameters( asym_session->u.s.dsa = dsa; asym_session->xfrm_type = RTE_CRYPTO_ASYM_XFORM_DSA; break; - +#endif err_dsa: BN_free(p); BN_free(q); @@ -1227,7 +1277,7 @@ static int openssl_set_asym_session_parameters( return -1; } default: - return -1; + return ret; } return 0; @@ -1310,8 +1360,12 @@ static void openssl_reset_asym_session(struct openssl_asym_session *sess) #endif break; case RTE_CRYPTO_ASYM_XFORM_DSA: +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + sess->u.s.param_bld = NULL; +#else if (sess->u.s.dsa) DSA_free(sess->u.s.dsa); +#endif break; default: break; -- 2.17.1