Replies: 4 comments 3 replies
-
Hmm, Would you be able to write a short demonstrator program that we can test with? |
Beta Was this translation helpful? Give feedback.
-
Sure, I already have one (click to expand)#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/provider.h>
#include <openssl/store.h>
void print_hex(unsigned char *data, size_t length) {
for (size_t i = 0; i < length; i++) {
printf("%02x", data[i]);
}
}
int do_sha256(unsigned char* data, int dataLen, unsigned char** hashOut) {
printf("do_sha256\n");
int hashLen = SHA256_DIGEST_LENGTH;
unsigned char* hash = OPENSSL_malloc(hashLen);
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
const EVP_MD *md = EVP_sha256();
EVP_DigestInit_ex(mdctx, md, NULL);
EVP_DigestUpdate(mdctx, data, dataLen);
EVP_DigestFinal_ex(mdctx, hash, NULL);
EVP_MD_CTX_free(mdctx);
*hashOut = hash;
return hashLen;
}
void do_stuff_with_evp_pkey2(EVP_PKEY* pkey) {
printf("do_stuff_with_evp_pkey2 (problematic)\n");
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); // we're not passing libCtx here
if (ctx == NULL) {
fprintf(stderr, "Failed to create EVP_PKEY_CTX\n");
return;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Failed to set RSA padding to PSS\n");
return;
}
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Failed to set signature hash function to SHA256\n");
return;
}
EVP_PKEY_CTX_free(ctx);
}
void do_stuff_with_evp_pkey(EVP_PKEY_CTX* ctx) {
printf("do_stuff_with_evp_pkey\n");
int sign_init_result = EVP_PKEY_sign_init(ctx);
if (sign_init_result > 0) {
// Set the signature algorithm to RSASSA-PSS
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Failed to set RSA padding to PSS\n");
return;
}
// Set the hash function to SHA256
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Failed to set signature hash function to SHA256\n");
return;
}
}
}
void do_more_stuff_with_evp_pkey(EVP_PKEY_CTX* ctx) {
printf("do_more_stuff_with_evp_pkey\n");
unsigned char* hash;
size_t siglen;
unsigned char data[] = "testdata\0";
int dataLen = strlen((char*)data) + 1;
int hashLen = do_sha256(data, dataLen, &hash);
// Determine the size of the signature
printf("hashLen=%d\n", hashLen);
if (EVP_PKEY_sign(ctx, NULL, &siglen, hash, hashLen) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Failed to determine signature size\n");
return;
}
printf("EVP_PKEY_sign returned that signature is %d bytes long\n", (int)siglen);
// Allocate memory for the signature
unsigned char *sig = OPENSSL_malloc(siglen);
if (sig == NULL) {
fprintf(stderr, "Failed to allocate memory for signature\n");
return;
}
printf("EVP_PKEY_sign\n");
// Perform the signing operation
if (EVP_PKEY_sign(ctx, sig, &siglen, hash, hashLen) <= 0) {
ERR_print_errors_fp(stderr);
fprintf(stderr, "Failed to sign data\n");
return;
}
printf("Seems all is good!\n");
printf("Hash:\n");
print_hex(hash, hashLen);
printf("\nSignature\n");
print_hex(sig, siglen);
printf("\n");
// At this point, 'sig' contains the signature and 'siglen' is its length
OPENSSL_free(sig);
}
EVP_PKEY* extract_key(OSSL_LIB_CTX* libCtx, const char* keyUri) {
printf("extract_key\n");
EVP_PKEY* pkey = NULL;
printf("openning the store\n");
OSSL_STORE_CTX *store_ctx = OSSL_STORE_open_ex(keyUri, libCtx, NULL, NULL, NULL, NULL, NULL, NULL);
if (store_ctx == NULL) {
fprintf(stderr, "Failed to open store\n");
return NULL;
}
OSSL_STORE_INFO *info;
// Retrieve each key from the store and check if it's suitable for signing
int key_index = 0;
while (!OSSL_STORE_eof(store_ctx) && (info = OSSL_STORE_load(store_ctx)) != NULL) {
printf("Something found in OSSL_STORE\n");
if (OSSL_STORE_error(store_ctx)) {
fprintf(stderr, "OSSL_STORE_error returned 1\n");
ERR_print_errors_fp(stderr);
// per OpenSSL docs:
// Note that it may still be meaningful to try and load more objects
if (OSSL_STORE_eof(store_ctx))
{
break;
}
continue;
}
int store_type = OSSL_STORE_INFO_get_type(info);
if (store_type == OSSL_STORE_INFO_PKEY) {
if (pkey != NULL) {
printf("Found more than one key in the store, using the first one\n");
OSSL_STORE_INFO_free(info);
info = NULL;
break;
}
pkey = OSSL_STORE_INFO_get1_PKEY(info);
if (pkey != NULL) {
printf("Found key at index: %d\n", key_index);
} else {
printf("Failed to get key from store info at index: %d\n", key_index);
}
} else {
printf("Key index: %d is not suitable for signing because store type is %d\n", key_index, store_type);
}
OSSL_STORE_INFO_free(info);
//OSSL_STORE_close(store_ctx); // <-- TODO: do we need to keep lifetime of this handle? Uncommenting causes segmentation fault
info = NULL;
key_index++;
}
if (pkey == NULL) {
if (OSSL_STORE_error(store_ctx)) {
fprintf(stderr, "OSSL_STORE_error returned 1 and there was no suitable key for signing\n");
ERR_print_errors_fp(stderr);
}
fprintf(stderr, "Failed to find a suitable key for signing\n");
}
return pkey;
}
void export_pubkey(EVP_PKEY* pkey) {
printf("export_pubkey\n");
BIO* pubKeyBio = BIO_new_file("testprovider.exported.pub", "w");
if (pubKeyBio == NULL) {
printf("Failed to open testprovider.exported.pub file\n");
return;
}
if (PEM_write_bio_PUBKEY(pubKeyBio, pkey) != 1) {
fprintf(stderr, "Failed to write public key to file\n");
}
BIO_free(pubKeyBio);
}
int main() {
OSSL_LIB_CTX* libCtx = OSSL_LIB_CTX_new();
OSSL_PROVIDER *prov = OSSL_PROVIDER_load(libCtx, "tpm2");
if (prov == NULL) {
fprintf(stderr, "Failed to load TPM2 provider\n");
return 1;
}
EVP_PKEY* pkey = extract_key(libCtx, "handle:0x81000004");
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_from_pkey(libCtx, pkey, NULL);
//EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); // <-- problematic (lack of libCtx)
if (ctx == NULL) {
printf("Failed to create context\n");
}
do_stuff_with_evp_pkey(ctx);
do_stuff_with_evp_pkey2(pkey);
do_more_stuff_with_evp_pkey(ctx);
EVP_PKEY_CTX_free(ctx);
ctx = NULL;
export_pubkey(pkey);
EVP_PKEY_free(pkey);
pkey = NULL;
OSSL_PROVIDER_unload(prov);
OSSL_LIB_CTX_free(libCtx);
return 0;
} Search for commented out: please let me know if you need help with creating a key for tpm2 provider - I'm not certain if it's related to this repro but you'll definitely need to adjust I'm using |
Beta Was this translation helpful? Give feedback.
-
ping @levitte |
Beta Was this translation helpful? Give feedback.
-
It took me a moment to get back to this. Unfortunately, the example code in #23691 (comment) has a bug, diff -u /home/levitte/tmp/foo.c.orig /home/levitte/tmp/foo.c
--- /home/levitte/tmp/foo.c.orig 2024-04-17 08:50:40.091073491 +0200
+++ /home/levitte/tmp/foo.c 2024-04-17 08:51:49.335056135 +0200
@@ -164,7 +165,6 @@
}
OSSL_STORE_INFO_free(info);
- //OSSL_STORE_close(store_ctx); // <-- TODO: do we need to keep lifetime of this handle? Uncommenting causes segmentation fault
info = NULL;
key_index++;
}
@@ -178,6 +178,8 @@
fprintf(stderr, "Failed to find a suitable key for signing\n");
}
+ OSSL_STORE_close(store_ctx); // <-- TODO: do we need to keep lifetime of this handle? Uncommenting causes segmentation fault
+
return pkey;
}
I've tested this against a PEM file, by changing diff -u /home/levitte/tmp/foo.c.orig /home/levitte/tmp/foo.c
--- /home/levitte/tmp/foo.c.orig 2024-04-17 08:50:40.091073491 +0200
+++ /home/levitte/tmp/foo.c 2024-04-17 08:51:49.335056135 +0200
@@ -2,6 +2,7 @@
#include <openssl/evp.h>
#include <openssl/provider.h>
#include <openssl/store.h>
+#include <openssl/err.h>
void print_hex(unsigned char *data, size_t length) {
for (size_t i = 0; i < length; i++) {
@@ -198,14 +200,16 @@
int main() {
OSSL_LIB_CTX* libCtx = OSSL_LIB_CTX_new();
+#if 0
OSSL_PROVIDER *prov = OSSL_PROVIDER_load(libCtx, "tpm2");
if (prov == NULL) {
fprintf(stderr, "Failed to load TPM2 provider\n");
return 1;
}
+#endif
- EVP_PKEY* pkey = extract_key(libCtx, "handle:0x81000004");
+ EVP_PKEY* pkey = extract_key(libCtx, "file:///home/levitte/gitwrk/openssl.net/official/master/test/certs/leaf.key");
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_from_pkey(libCtx, pkey, NULL);
//EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); // <-- problematic (lack of libCtx)
@@ -224,7 +228,9 @@
EVP_PKEY_free(pkey);
pkey = NULL;
+#if 0
OSSL_PROVIDER_unload(prov);
+#endif
OSSL_LIB_CTX_free(libCtx);
return 0; That works with no problem: $ cc -o foo foo.c -lcrypto
$ ./foo
extract_key
openning the store
Something found in OSSL_STORE
Found key at index: 0
do_stuff_with_evp_pkey
do_stuff_with_evp_pkey2 (problematic)
C0FEB819937F0000:error:03000095:digital envelope routines:evp_pkey_ctx_ctrl_int:no operation set:../crypto/evp/pmeth_lib.c:1236:
Failed to set RSA padding to PSS
do_more_stuff_with_evp_pkey
do_sha256
hashLen=32
EVP_PKEY_sign returned that signature is 256 bytes long
EVP_PKEY_sign
Seems all is good!
Hash:
e20ed328f4ea52fb44a658fa7d798efc6c832bfdf5c8ef1401a95a7b9628b4df
Signature
a120c7aa4cf008f927a9ac78198120090e55cf893a50a6966a4080ad11440bf8f72d8a18acfbc2fa3689a38eb2b6b8af6a07ca896c1460dd0e52ffc41f93d46792d3e63649cdc4a23b6dc14aed85a91019bbf79a594b7c743bfab947b16df270cfa2453e5d4a36a4e65ad4ec9f47171af166d1d18d72adb1772c601d80804de59d49d9627638c2dde79585706908f8b02d1685e5670a1e8ece4574e893a2d861e0f8b12b25d26c7d9888cc6af62407f73b5d94a3d4a21b0d8fc3adcb47c31098a5e53ca1037f979e0ffe9e51fbbaaa3fdaf8a023d55551d764e3b7d115585a8217a7daae354d0736fa6c5b9bfd48a7c565f002eccd6cc0f33444091a00997e56
export_pubkey So, question is if the problem with the tpm2 provider remains if |
Beta Was this translation helpful? Give feedback.
-
I'm creating a method which I hoped would take OSSL_LIB_CTX and key uri as input and return EVP_PKEY. Method would search for specific EVP_PKEY first by openning OSSL_STORE_open_ex and then OSSL_STORE_load + OSSL_STORE_eof - at one point when key matches some criteria I'd like to get a copy by using get1 function: OSSL_STORE_INFO_get1_PKEY. When I'm exiting my search subroutine I'm freeing all OSSL_STORE_INFO and call OSSL_STORE_close - it turns out that when I close the EVP_PKEY is no longer valid and I'm forced to hold both OSSL_STORE_CTX references for the rest of the lifetime of the key. I'm not sure if this is by design but it seems rather unfortunate. The key is related to the tpm2 provider which is loaded into the OSSL_LIB_CTX.
Is there some other way I can achieve what I described above? Any guidance or something else I might be overcomplicating here? I can provide entire repro app or specific function and how and how to create repro environment if needed.
Beta Was this translation helpful? Give feedback.
All reactions