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 d18149e5..ede1782c 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 { @@ -108,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; } @@ -438,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; @@ -941,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; @@ -4027,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) { @@ -4149,3 +4153,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 diff --git a/src/signature.c b/src/signature.c index 10465962..43872106 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; } @@ -1252,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; @@ -1903,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; 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); +}