Skip to content

Commit

Permalink
Fix #372: expose hybrid_classical_ and hybrid_pq_ OSSL_PARAMS f…
Browse files Browse the repository at this point in the history
…or `EVP_PKEY`.

This commit is an attempt to fix #372, by adding four new [`OSSL_PARAM`] to
[`EVP_PKEY`].

The following [`OSSL_PARAM`] are added by this commit:
  - `hybrid_classical_pub`: an octet string to the classical public key.
  - `hybrid_classical_priv`: an octet string to the classical private key.
  - `hybrid_pq_pub`: an octet string to the quantum-resistant public key.
  - `hybrid_pq_priv`: an octet string to the quantum-resistant private key.

Using [`EVP_PKEY_get_params`], OpenSSL users should be able to extract the
specific subkey they want from an hybrid key.

A test called `test_evp_pkey_params` has been added to ensure that it works
with all hybrid algorithms, to also ensure that the output of these parameters
are consistent between each other.

[`OSSL_PARAM`]: https://www.openssl.org/docs/man3.2/man3/OSSL_PARAM.html
[`EVP_PKEY`]: https://www.openssl.org/docs/man3.2/man7/evp.html
[`EVP_PKEY_get_params`]: https://www.openssl.org/docs/man3.2/man3/EVP_PKEY_get_params.html

Signed-off-by: thb-sb <[email protected]>
  • Loading branch information
thb-sb committed Mar 14, 2024
1 parent f08657b commit a6eda7f
Show file tree
Hide file tree
Showing 6 changed files with 745 additions and 3 deletions.
111 changes: 108 additions & 3 deletions oqsprov/oqs_kmgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,25 @@ static int oqsx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
return ok;
}

#define OQS_KEY_TYPES() \
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), \
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0)
#define OSSL_HYBRID_PKEY_PARAM_CLASSICAL_PUB_KEY \
"hybrid_classical_" OSSL_PKEY_PARAM_PUB_KEY
#define OSSL_HYBRID_PKEY_PARAM_CLASSICAL_PRIV_KEY \
"hybrid_classical_" OSSL_PKEY_PARAM_PRIV_KEY
#define OSSL_HYBRID_PKEY_PARAM_PQ_PUB_KEY "hybrid_pq_" OSSL_PKEY_PARAM_PUB_KEY
#define OSSL_HYBRID_PKEY_PARAM_PQ_PRIV_KEY "hybrid_pq_" OSSL_PKEY_PARAM_PRIV_KEY

#define OQS_HYBRID_KEY_TYPES() \
OSSL_PARAM_octet_string(OSSL_HYBRID_PKEY_PARAM_CLASSICAL_PUB_KEY, NULL, \
0), \
OSSL_PARAM_octet_string(OSSL_HYBRID_PKEY_PARAM_CLASSICAL_PRIV_KEY, \
NULL, 0), \
OSSL_PARAM_octet_string(OSSL_HYBRID_PKEY_PARAM_PQ_PUB_KEY, NULL, 0), \
OSSL_PARAM_octet_string(OSSL_HYBRID_PKEY_PARAM_PQ_PRIV_KEY, NULL, 0)

#define OQS_KEY_TYPES() \
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), \
OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), \
OQS_HYBRID_KEY_TYPES()

static const OSSL_PARAM oqsx_key_types[] = {OQS_KEY_TYPES(), OSSL_PARAM_END};
static const OSSL_PARAM *oqs_imexport_types(int selection)
Expand All @@ -327,6 +343,92 @@ static const OSSL_PARAM *oqs_imexport_types(int selection)
return NULL;
}

// Tells if a key (SIG, KEM, ECP_HYB_KEM, ECX_HYB_KEM or HYB_SIG) is using
// hybrid algorithm.
//
// Returns 1 if hybrid, else 0.
static int oqsx_key_is_hybrid(const OQSX_KEY *oqsxk)
{
if ((oqsxk->keytype == KEY_TYPE_ECP_HYB_KEM
|| oqsxk->keytype == KEY_TYPE_ECX_HYB_KEM
|| oqsxk->keytype == KEY_TYPE_HYB_SIG)
&& oqsxk->numkeys == 2 && oqsxk->classical_pkey != NULL) {
OQS_KM_PRINTF("OQSKEYMGMT: key is hybrid\n");
return 1;
}
return 0;
}

// Gets the classical params of an hybrid key.

// Gets hybrid params.
//
// Returns 0 on success.
static int oqsx_get_hybrid_params(OQSX_KEY *key, OSSL_PARAM params[])
{
OSSL_PARAM *p;
const void *classical_pubkey = NULL;
const void *classical_privkey = NULL;
const void *pq_pubkey = NULL;
const void *pq_privkey = NULL;
int classical_pubkey_len = 0;
int classical_privkey_len = 0;
int pq_pubkey_len = 0;
int pq_privkey_len = 0;

if (oqsx_key_is_hybrid(key) != 1)
return 0;

if (key->numkeys != 2) {
OQS_KM_PRINTF2("OQSKEYMGMT: key is hybrid but key->numkeys = %zu\n",
key->numkeys);
ERR_raise(ERR_LIB_PROV, OQSPROV_R_INTERNAL_ERROR);
return -1;
}

if (key->comp_pubkey != NULL && key->pubkey != NULL) {
classical_pubkey = key->comp_pubkey[0];
DECODE_UINT32(classical_pubkey_len, key->pubkey);
}
if (key->comp_privkey != NULL && key->privkey != NULL) {
classical_privkey = key->comp_privkey[0];
DECODE_UINT32(classical_privkey_len, key->privkey);
}

if (key->comp_pubkey[1] != NULL) {
pq_pubkey = key->comp_pubkey[1];
pq_pubkey_len = key->pubkeylen - classical_pubkey_len - SIZE_OF_UINT32;
}
if (key->comp_privkey != NULL) {
pq_privkey = key->comp_privkey[1];
pq_privkey_len
= key->privkeylen - classical_privkey_len - SIZE_OF_UINT32;
}

if ((p
= OSSL_PARAM_locate(params, OSSL_HYBRID_PKEY_PARAM_CLASSICAL_PUB_KEY))
!= NULL
&& !OSSL_PARAM_set_octet_string(p, classical_pubkey,
classical_pubkey_len))
return -1;
if ((p
= OSSL_PARAM_locate(params, OSSL_HYBRID_PKEY_PARAM_CLASSICAL_PRIV_KEY))
!= NULL
&& !OSSL_PARAM_set_octet_string(p, classical_privkey,
classical_privkey_len))
return -1;
if ((p = OSSL_PARAM_locate(params, OSSL_HYBRID_PKEY_PARAM_PQ_PUB_KEY))
!= NULL
&& !OSSL_PARAM_set_octet_string(p, pq_pubkey, pq_pubkey_len))
return -1;
if ((p = OSSL_PARAM_locate(params, OSSL_HYBRID_PKEY_PARAM_PQ_PRIV_KEY))
!= NULL
&& !OSSL_PARAM_set_octet_string(p, pq_privkey, pq_privkey_len))
return -1;

return 0;
}

// must handle param requests for KEM and SIG keys...
static int oqsx_get_params(void *key, OSSL_PARAM params[])
{
Expand Down Expand Up @@ -384,6 +486,9 @@ static int oqsx_get_params(void *key, OSSL_PARAM params[])
return 0;
}

if (oqsx_get_hybrid_params(oqsxk, params))
return 0;

// not passing in params to respond to is no error
return 1;
}
Expand Down
1 change: 1 addition & 0 deletions oqsprov/oqs_prov.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#define OQSPROV_R_WRONG_PARAMETERS 13
#define OQSPROV_R_VERIFY_ERROR 14
#define OQSPROV_R_EVPINFO_MISSING 15
#define OQSPROV_R_INTERNAL_ERROR 16

/* Extras for OQS extension */

Expand Down
1 change: 1 addition & 0 deletions oqsprov/oqs_sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/params.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>

// TBD: Review what we really need/want: For now go with OSSL settings:
Expand Down
1 change: 1 addition & 0 deletions oqsprov/oqsprov_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/params.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <string.h>

Expand Down
21 changes: 21 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,32 @@ set_tests_properties(oqs_endecode
)
endif()

add_executable(oqs_test_evp_pkey_params oqs_test_evp_pkey_params.c test_common.c)
target_link_libraries(oqs_test_evp_pkey_params PRIVATE ${OPENSSL_CRYPTO_LIBRARY} ${OQS_ADDL_SOCKET_LIBS})
add_test(
NAME oqs_evp_pkey_params
COMMAND oqs_test_evp_pkey_params
"oqsprovider"
"${CMAKE_CURRENT_SOURCE_DIR}/openssl-ca.cnf"
)
# openssl under MSVC seems to have a bug registering NIDs:
# It only works when setting OPENSSL_CONF, not when loading the same cnf file:
if (MSVC)
set_tests_properties(oqs_evp_pkey_params
PROPERTIES ENVIRONMENT "OPENSSL_MODULES=${OQS_PROV_BINARY_DIR};OPENSSL_CONF=${CMAKE_CURRENT_SOURCE_DIR}/openssl-ca.cnf"
)
else()
set_tests_properties(oqs_evp_pkey_params
PROPERTIES ENVIRONMENT "OPENSSL_MODULES=${OQS_PROV_BINARY_DIR}"
)
endif()

if (OQS_PROVIDER_BUILD_STATIC)
targets_set_static_provider(oqs_test_signatures
oqs_test_kems
oqs_test_groups
oqs_test_tlssig
oqs_test_endecode
oqs_test_evp_pkey_params
)
endif()
Loading

0 comments on commit a6eda7f

Please sign in to comment.