summaryrefslogtreecommitdiffstats
path: root/providers
diff options
context:
space:
mode:
authorpohsingwu <pohsingwu@synology.com>2024-01-28 18:18:02 +0800
committerTomas Mraz <tomas@openssl.org>2024-03-01 11:06:03 +0100
commitfbce6ebf706cdd273f2569edfea7ade106426e0b (patch)
tree2d598acb71f57e2fe8af34857e00126020e8cbb6 /providers
parentc18c301deb44deb27f35c199e8bf44ca8b80e579 (diff)
Implement PCT for EDDSA
According to FIPS 140-3 IG 10.3.A Additonal Comment 1, a PCT shall be performed consistent with the intended use of the keys. This commit implements PCT for EDDSA via performing sign and verify operations after key generated. Also use the same pairwise test logic in EVP_PKEY_keygen and EVP_PKEY_pairwise_check for EDDSA in FIPS_MODULE. Add OSSL_SELF_TEST_DESC_PCT_EDDSA to OSSL_PROVIDER-FIPS page. Reviewed-by: Paul Dale <ppzgs1@gmail.com> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/23408)
Diffstat (limited to 'providers')
-rw-r--r--providers/implementations/keymgmt/ecx_kmgmt.c142
1 files changed, 134 insertions, 8 deletions
diff --git a/providers/implementations/keymgmt/ecx_kmgmt.c b/providers/implementations/keymgmt/ecx_kmgmt.c
index 8a9fe1b21b..ae11fd4bc0 100644
--- a/providers/implementations/keymgmt/ecx_kmgmt.c
+++ b/providers/implementations/keymgmt/ecx_kmgmt.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -16,6 +16,7 @@
#include <openssl/proverr.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
+#include <openssl/self_test.h>
#include "internal/param_build_set.h"
#include <openssl/param_build.h>
#include "crypto/ecx.h"
@@ -588,6 +589,74 @@ static const OSSL_PARAM *ecx_gen_settable_params(ossl_unused void *genctx,
return settable;
}
+#ifdef FIPS_MODULE
+/*
+ * Refer: FIPS 140-3 IG 10.3.A Additional Comment 1
+ * Perform a pairwise test for EDDSA by signing and verifying signature.
+ *
+ * The parameter `self_test` is used to indicate whether to create OSSL_SELF_TEST
+ * instance.
+ */
+static int ecd_fips140_pairwise_test(const ECX_KEY *ecx, int type, int self_test)
+{
+ int ret = 0;
+ OSSL_SELF_TEST *st = NULL;
+ OSSL_CALLBACK *cb = NULL;
+ void *cbarg = NULL;
+
+ unsigned char msg[16] = {0};
+ size_t msg_len = sizeof(msg);
+ unsigned char sig[ED448_SIGSIZE] = {0};
+
+ int is_ed25519 = (type == ECX_KEY_TYPE_ED25519) ? 1 : 0;
+ int operation_result = 0;
+
+ /*
+ * The functions `OSSL_SELF_TEST_*` will return directly if parameter `st`
+ * is NULL.
+ */
+ if (self_test) {
+ OSSL_SELF_TEST_get_callback(ecx->libctx, &cb, &cbarg);
+
+ st = OSSL_SELF_TEST_new(cb, cbarg);
+ if (st == NULL)
+ return 0;
+ }
+
+ OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT,
+ OSSL_SELF_TEST_DESC_PCT_EDDSA);
+
+ if (is_ed25519)
+ operation_result = ossl_ed25519_sign(sig, msg, msg_len, ecx->pubkey,
+ ecx->privkey, 0, 0, 0, NULL, 0,
+ ecx->libctx, ecx->propq);
+ else
+ operation_result = ossl_ed448_sign(ecx->libctx, sig, msg, msg_len,
+ ecx->pubkey, ecx->privkey, NULL, 0,
+ 0, ecx->propq);
+ if (operation_result != 1)
+ goto err;
+
+ OSSL_SELF_TEST_oncorrupt_byte(st, sig);
+
+ if (is_ed25519)
+ operation_result = ossl_ed25519_verify(msg, msg_len, sig, ecx->pubkey,
+ 0, 0, 0, NULL, 0, ecx->libctx,
+ ecx->propq);
+ else
+ operation_result = ossl_ed448_verify(ecx->libctx, msg, msg_len, sig,
+ ecx->pubkey, NULL, 0, 0, ecx->propq);
+ if (operation_result != 1)
+ goto err;
+
+ ret = 1;
+err:
+ OSSL_SELF_TEST_onend(st, ret);
+ OSSL_SELF_TEST_free(st);
+ return ret;
+}
+#endif
+
static void *ecx_gen(struct ecx_gen_ctx *gctx)
{
ECX_KEY *key;
@@ -684,6 +753,7 @@ static void *x448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
{
+ ECX_KEY *key = NULL;
struct ecx_gen_ctx *gctx = genctx;
if (!ossl_prov_is_running())
@@ -693,14 +763,31 @@ static void *ed25519_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED25519)
&& OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED25519)
&& OPENSSL_s390xcap_P.kdsa[0]
- & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED25519))
- return s390x_ecd_keygen25519(gctx);
+ & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED25519)) {
+ key = s390x_ecd_keygen25519(gctx);
+ } else
#endif
- return ecx_gen(gctx);
+ {
+ key = ecx_gen(gctx);
+ }
+
+#ifdef FIPS_MODULE
+ /* Exit if keygen failed OR we are doing parameter generation (blank key) */
+ if (!key || ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0))
+ return key;
+ if (ecd_fips140_pairwise_test(key, ECX_KEY_TYPE_ED25519, 1) != 1) {
+ ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
+ ossl_ecx_key_free(key);
+ return NULL;
+ }
+#endif
+
+ return key;
}
static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
{
+ ECX_KEY *key = NULL;
struct ecx_gen_ctx *gctx = genctx;
if (!ossl_prov_is_running())
@@ -709,10 +796,26 @@ static void *ed448_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
#ifdef S390X_EC_ASM
if (OPENSSL_s390xcap_P.pcc[1] & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_ED448)
&& OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_SIGN_ED448)
- && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED448))
- return s390x_ecd_keygen448(gctx);
+ && OPENSSL_s390xcap_P.kdsa[0] & S390X_CAPBIT(S390X_EDDSA_VERIFY_ED448)) {
+ key = s390x_ecd_keygen448(gctx);
+ } else
#endif
- return ecx_gen(gctx);
+ {
+ key = ecx_gen(gctx);
+ }
+
+#ifdef FIPS_MODULE
+ /* Exit if keygen failed OR we are doing parameter generation (blank key) */
+ if (!key || ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0))
+ return key;
+ if (ecd_fips140_pairwise_test(key, ECX_KEY_TYPE_ED448, 1) != 1) {
+ ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
+ ossl_ecx_key_free(key);
+ return NULL;
+ }
+#endif
+
+ return key;
}
static void ecx_gen_cleanup(void *genctx)
@@ -756,6 +859,23 @@ static int ecx_key_pairwise_check(const ECX_KEY *ecx, int type)
case ECX_KEY_TYPE_X448:
ossl_x448_public_from_private(pub, ecx->privkey);
break;
+ default:
+ return 0;
+ }
+ return CRYPTO_memcmp(ecx->pubkey, pub, ecx->keylen) == 0;
+}
+
+#ifdef FIPS_MODULE
+static int ecd_key_pairwise_check(const ECX_KEY *ecx, int type)
+{
+ return ecd_fips140_pairwise_test(ecx, type, 0);
+}
+#else
+static int ecd_key_pairwise_check(const ECX_KEY *ecx, int type)
+{
+ uint8_t pub[64];
+
+ switch (type) {
case ECX_KEY_TYPE_ED25519:
if (!ossl_ed25519_public_from_private(ecx->libctx, pub, ecx->privkey,
ecx->propq))
@@ -771,6 +891,7 @@ static int ecx_key_pairwise_check(const ECX_KEY *ecx, int type)
}
return CRYPTO_memcmp(ecx->pubkey, pub, ecx->keylen) == 0;
}
+#endif
static int ecx_validate(const void *keydata, int selection, int type, size_t keylen)
{
@@ -794,7 +915,12 @@ static int ecx_validate(const void *keydata, int selection, int type, size_t key
if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
ok = ok && ecx->privkey != NULL;
- if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR)
+ if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != OSSL_KEYMGMT_SELECT_KEYPAIR)
+ return ok;
+
+ if (type == ECX_KEY_TYPE_ED25519 || type == ECX_KEY_TYPE_ED448)
+ ok = ok && ecd_key_pairwise_check(ecx, type);
+ else
ok = ok && ecx_key_pairwise_check(ecx, type);
return ok;