From 2b9df2d6d227f0d1ab5c11b4354f505d6907fee1 Mon Sep 17 00:00:00 2001 From: Kirill Ermoshin Date: Thu, 5 Dec 2024 13:18:08 +0300 Subject: [PATCH 1/5] Add public key object pointer to P11PROV_OBJ EVP_PKEY_generate returns only one EVP_PKEY instance for private and public keys. This requires storing the public key object in the private key object in order to use it for operations that using the public key Signed-off-by: latal-1 --- src/objects.c | 18 ++++++++++++++++++ src/objects.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/src/objects.c b/src/objects.c index d18149e5..be7bed0e 100644 --- a/src/objects.c +++ b/src/objects.c @@ -40,6 +40,8 @@ struct p11prov_obj { CK_BBOOL cka_copyable; CK_BBOOL cka_token; + P11PROV_OBJ *pub_key_obj; + P11PROV_URI *refresh_uri; union { @@ -4149,3 +4151,19 @@ P11PROV_OBJ *mock_pub_ec_key(P11PROV_CTX *ctx, CK_ATTRIBUTE_TYPE type, return key; } + +CK_RV p11prov_set_pub(P11PROV_OBJ *priv, P11PROV_OBJ *pub) +{ + if (!priv || !pub) return CKR_ARGUMENTS_BAD; + if (priv->class != CKO_PRIVATE_KEY || pub->class != CKO_PUBLIC_KEY) + return CKR_ARGUMENTS_BAD; + if (priv->pub_key_obj) return CKR_ARGUMENTS_BAD; + priv->pub_key_obj = pub; + return CKR_OK; +} + +P11PROV_OBJ *p11prov_get_pub(P11PROV_OBJ *priv) +{ + if (!priv || priv->class != CKO_PRIVATE_KEY) return NULL; + return priv->pub_key_obj; +} diff --git a/src/objects.h b/src/objects.h index c6ee04ff..3d8532ea 100644 --- a/src/objects.h +++ b/src/objects.h @@ -62,6 +62,8 @@ int p11prov_obj_get_ed_pub_key(P11PROV_OBJ *obj, CK_ATTRIBUTE **pub); CK_ATTRIBUTE *p11prov_obj_get_ec_public_raw(P11PROV_OBJ *key); P11PROV_OBJ *mock_pub_ec_key(P11PROV_CTX *ctx, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *ec_params); +CK_RV p11prov_set_pub(P11PROV_OBJ *priv, P11PROV_OBJ *pub); +P11PROV_OBJ *p11prov_get_pub(P11PROV_OBJ *priv); #define OBJ_CMP_KEY_TYPE 0x00 #define OBJ_CMP_KEY_PUBLIC 0x01 From 6f1a7874500daea0dbebae0abd90df90ec05ea4a Mon Sep 17 00:00:00 2001 From: Kirill Ermoshin Date: Thu, 5 Dec 2024 13:19:00 +0300 Subject: [PATCH 2/5] Use public key object from P11PROV_OBJ during generate and verify Signed-off-by: latal-1 --- src/keymgmt.c | 9 +++++++-- src/objects.c | 3 +++ src/signature.c | 16 ++++++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/keymgmt.c b/src/keymgmt.c index 68b451b4..70299292 100644 --- a/src/keymgmt.c +++ b/src/keymgmt.c @@ -482,14 +482,19 @@ static int p11prov_common_gen(struct key_generator *ctx, } ret = p11prov_merge_pub_attrs_into_priv(pub_key, priv_key); + if (ret != CKR_OK) { + goto done; + } + + ret = p11prov_set_pub(priv_key, pub_key); done: if (ret != CKR_OK) { + p11prov_obj_free(pub_key); p11prov_obj_free(priv_key); - priv_key = NULL; + pub_key = priv_key = NULL; } p11prov_return_session(session); - p11prov_obj_free(pub_key); *key = priv_key; return ret; } diff --git a/src/objects.c b/src/objects.c index be7bed0e..283f88fb 100644 --- a/src/objects.c +++ b/src/objects.c @@ -440,6 +440,9 @@ void p11prov_obj_free(P11PROV_OBJ *obj) if (obj == NULL) { return; } + + p11prov_obj_free(obj->pub_key_obj); + if (__atomic_sub_fetch(&obj->refcnt, 1, __ATOMIC_SEQ_CST) != 0) { P11PROV_debug("object free: reference held"); return; diff --git a/src/signature.c b/src/signature.c index 10465962..e0bbb8ca 100644 --- a/src/signature.c +++ b/src/signature.c @@ -686,11 +686,7 @@ static CK_RV p11prov_sig_op_init(void *ctx, void *provkey, CK_FLAGS operation, return ret; } - sigctx->key = p11prov_obj_ref(key); - if (sigctx->key == NULL) { - return CKR_KEY_NEEDED; - } - class = p11prov_obj_get_class(sigctx->key); + class = p11prov_obj_get_class(key); switch (operation) { case CKF_SIGN: if (class != CKO_PRIVATE_KEY) { @@ -699,17 +695,25 @@ static CK_RV p11prov_sig_op_init(void *ctx, void *provkey, CK_FLAGS operation, break; case CKF_VERIFY: if (class != CKO_PUBLIC_KEY) { - return CKR_KEY_TYPE_INCONSISTENT; + key = p11prov_get_pub(key); + if (key == NULL) { + return CKR_KEY_TYPE_INCONSISTENT; + } } break; default: return CKR_GENERAL_ERROR; } + sigctx->key = p11prov_obj_ref(key); + if (sigctx->key == NULL) { + return CKR_KEY_NEEDED; + } sigctx->operation = operation; if (digest) { ret = p11prov_digest_get_by_name(digest, &sigctx->digest); if (ret != CKR_OK) { + p11prov_obj_free(sigctx->key); ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return ret; } From 57fb91adea33b021c43e6d4f6b95147cd02743da Mon Sep 17 00:00:00 2001 From: Kirill Ermoshin Date: Thu, 5 Dec 2024 13:23:39 +0300 Subject: [PATCH 3/5] Remove reinitialization of P11PROV_OBJ some fields Signed-off-by: latal-1 --- src/objects.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/objects.c b/src/objects.c index 283f88fb..118c7c39 100644 --- a/src/objects.c +++ b/src/objects.c @@ -946,8 +946,6 @@ CK_RV p11prov_obj_from_handle(P11PROV_CTX *ctx, P11PROV_SESSION *session, if (obj == NULL) { return CKR_HOST_MEMORY; } - obj->handle = handle; - obj->slotid = p11prov_session_slotid(session); obj->data.key.type = CK_UNAVAILABLE_INFORMATION; num = 0; From 9fd45c3c9623ae91da9f22f17b5a497b55b4c3b9 Mon Sep 17 00:00:00 2001 From: Kirill Ermoshin Date: Thu, 5 Dec 2024 13:23:50 +0300 Subject: [PATCH 4/5] Reformat some files with clang-format Signed-off-by: latal-1 --- src/objects.c | 5 +++-- src/signature.c | 14 ++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/objects.c b/src/objects.c index 118c7c39..ede1782c 100644 --- a/src/objects.c +++ b/src/objects.c @@ -110,8 +110,8 @@ void p11prov_obj_pool_free(P11PROV_OBJ_POOL *pool) } OPENSSL_free(pool->objects); (void)MUTEX_UNLOCK(pool); - /* ------------- LOCKED SECTION */ } - else { + /* ------------- LOCKED SECTION */ + } else { P11PROV_debug("Failed to lock object pool, leaking it!"); return; } @@ -4030,6 +4030,7 @@ CK_RV p11prov_obj_copy_specific_attr(P11PROV_OBJ *pub_key, #define RSA_PRIV_ATTRS_NUM 2 #define EC_PRIV_ATTRS_NUM 3 +// TODO: maybe remove after public key object was added in P11PROV_OBJ CK_RV p11prov_merge_pub_attrs_into_priv(P11PROV_OBJ *pub_key, P11PROV_OBJ *priv_key) { diff --git a/src/signature.c b/src/signature.c index e0bbb8ca..43872106 100644 --- a/src/signature.c +++ b/src/signature.c @@ -1256,10 +1256,9 @@ static int p11prov_rsasig_digest_sign_final(void *ctx, unsigned char *sig, /* the siglen might be uninitialized when called from openssl */ *siglen = 0; - P11PROV_debug( - "rsa digest sign final (ctx=%p, sig=%p, siglen=%zu, " - "sigsize=%zu)", - ctx, sig, *siglen, sigsize); + P11PROV_debug("rsa digest sign final (ctx=%p, sig=%p, siglen=%zu, " + "sigsize=%zu)", + ctx, sig, *siglen, sigsize); if (sigctx == NULL) { return RET_OSSL_ERR; @@ -1907,10 +1906,9 @@ static int p11prov_ecdsa_digest_sign_final(void *ctx, unsigned char *sig, /* the siglen might be uninitialized when called from openssl */ *siglen = 0; - P11PROV_debug( - "ecdsa digest sign final (ctx=%p, sig=%p, siglen=%zu, " - "sigsize=%zu)", - ctx, sig, *siglen, sigsize); + P11PROV_debug("ecdsa digest sign final (ctx=%p, sig=%p, siglen=%zu, " + "sigsize=%zu)", + ctx, sig, *siglen, sigsize); if (sigctx == NULL) { return RET_OSSL_ERR; From f5f049dc89dc22844de54ca29e5667d4696b0735 Mon Sep 17 00:00:00 2001 From: Kirill Ermoshin Date: Fri, 13 Dec 2024 22:11:59 +0300 Subject: [PATCH 5/5] Add test on sign and verify with generated keys Signed-off-by: latal-1 --- tests/meson.build | 1 + tests/tbasic | 4 ++ tests/tsigver.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 tests/tsigver.c diff --git a/tests/meson.build b/tests/meson.build index 3c640638..03f7f95d 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -106,6 +106,7 @@ test_programs = { 'tcmpkeys': ['tcmpkeys.c', 'util.c'], 'tfork': ['tfork.c'], 'pincache': ['pincache.c'], + 'tsigver': ['tsigver.c'], } test_executables = [] diff --git a/tests/tbasic b/tests/tbasic index 02c9ac88..c992e595 100755 --- a/tests/tbasic +++ b/tests/tbasic @@ -296,5 +296,9 @@ if [ $FAIL -ne 0 ]; then echo exit 1 fi +OPENSSL_CONF=${ORIG_OPENSSL_CONF} + +title PARA "Test sign and verify on generated keys" +$CHECKER "${TESTBLDDIR}/tsigver" exit 0 diff --git a/tests/tsigver.c b/tests/tsigver.c new file mode 100644 index 00000000..a4df6fca --- /dev/null +++ b/tests/tsigver.c @@ -0,0 +1,153 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +static void hexify(char *out, unsigned char *byte, size_t len) +{ + char c[2], s; + + for (size_t i = 0; i < len; i++) { + out[i * 3] = '%'; + c[0] = byte[i] >> 4; + c[1] = byte[i] & 0x0f; + for (int j = 0; j < 2; j++) { + if (c[j] < 0x0A) { + s = '0'; + } else { + s = 'a' - 10; + } + out[i * 3 + 1 + j] = c[j] + s; + } + } + out[len * 3] = '\0'; +} + +// TODO: add paddings +int main(int argc, char *argv[]) +{ + char *label; + unsigned char id[16]; + char idhex[16 * 3 + 1]; + char *uri; + size_t rsa_bits = 1024; + const char *key_usage = "digitalSignature"; + OSSL_PARAM params[4]; + int miniid; + EVP_PKEY_CTX *ctx; + EVP_PKEY *key = NULL; + // SHA-256 hash of "Plaintext Data" + const unsigned char md[] = { + 0xac, 0x26, 0x5c, 0x10, 0x09, 0xf8, 0xf4, 0xdf, 0x05, 0xf4, 0x25, + 0x18, 0x86, 0x92, 0x33, 0x5c, 0x2f, 0x9e, 0x9a, 0xe3, 0xdb, 0x44, + 0xc4, 0xa9, 0x12, 0xfd, 0xa5, 0x07, 0x7e, 0xd4, 0xe1, 0x76 + }; + unsigned char *sig; + size_t siglen; + int ret; + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11"); + if (ctx == NULL) { + fprintf(stderr, "Failed to init PKEY context for generate\n"); + exit(EXIT_FAILURE); + } + + ret = EVP_PKEY_keygen_init(ctx); + if (ret != 1) { + fprintf(stderr, "Failed to init keygen\n"); + exit(EXIT_FAILURE); + } + + ret = RAND_bytes(id, 16); + if (ret != 1) { + fprintf(stderr, "Failed to generate key id\n"); + exit(EXIT_FAILURE); + } + miniid = (id[0] << 24) + (id[1] << 16) + (id[2] << 8) + id[3]; + ret = asprintf(&label, "Test-RSA-gen-%08x", miniid); + if (ret == -1) { + fprintf(stderr, "Failed to make label\n"); + exit(EXIT_FAILURE); + } + hexify(idhex, id, 16); + ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); + if (ret == -1) { + fprintf(stderr, "Failed to compose PKCS#11 URI\n"); + exit(EXIT_FAILURE); + } + params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); + params[1] = OSSL_PARAM_construct_utf8_string("pkcs11_key_usage", + (char *)key_usage, 0); + params[2] = + OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &rsa_bits); + params[3] = OSSL_PARAM_construct_end(); + ret = EVP_PKEY_CTX_set_params(ctx, params); + if (ret != 1) { + fprintf(stderr, "Failed to set params\n"); + exit(EXIT_FAILURE); + } + + ret = EVP_PKEY_generate(ctx, &key); + if (ret != 1) { + fprintf(stderr, "Failed to generate key\n"); + exit(EXIT_FAILURE); + } + + EVP_PKEY_CTX_free(ctx); + + ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, "provider=pkcs11"); + if (ctx == NULL) { + fprintf(stderr, "Failed to init PKEY context for sign\n"); + exit(EXIT_FAILURE); + } + + ret = EVP_PKEY_sign_init(ctx); + if (ret != 1) { + fprintf(stderr, "Failed to init sign\n"); + exit(EXIT_FAILURE); + } + + ret = EVP_PKEY_sign(ctx, NULL, &siglen, md, sizeof(md) / sizeof(*md)); + if (ret != 1) { + fprintf(stderr, "Failed to determine buffer length\n"); + exit(EXIT_FAILURE); + } + sig = OPENSSL_malloc(siglen); + if (sig == NULL) { + fprintf(stderr, "Failed to malloc memory for buffer\n"); + exit(EXIT_FAILURE); + } + + ret = EVP_PKEY_sign(ctx, sig, &siglen, md, sizeof(md) / sizeof(*md)); + if (ret != 1) { + fprintf(stderr, "Failed to sign\n"); + exit(EXIT_FAILURE); + } + + EVP_PKEY_CTX_free(ctx); + + ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key, "provider=pkcs11"); + if (ctx == NULL) { + fprintf(stderr, "Failed to init PKEY context for verify\n"); + exit(EXIT_FAILURE); + } + + ret = EVP_PKEY_verify_init(ctx); + if (ret != 1) { + fprintf(stderr, "Failed to init verify\n"); + exit(EXIT_FAILURE); + } + + ret = EVP_PKEY_verify(ctx, sig, siglen, md, sizeof(md) / sizeof(*md)); + if (ret != 1) { + fprintf(stderr, "Failed to verify\n"); + exit(EXIT_FAILURE); + } + + OPENSSL_free(sig); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(key); + exit(EXIT_SUCCESS); +}