Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds encoding options for subjectPublicKey and privateKey #123

Merged
merged 4 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ jobs:
name: Run tests
command: |
./scripts/runtests.sh -V
- run:
name: Run tests (with encodings)
command: |
./scripts/runtests_encodings.sh -V
- run:
name: Build OQS-OpenSSL provider (only STD algs) with NOPUBKEY_IN_PRIVKEY
command: |
rm -rf _build && mkdir _build && cd _build && cmake -GNinja -DNOPUBKEY_IN_PRIVKEY=ON -DOPENSSL_ROOT_DIR=$(pwd)/../.local -DCMAKE_PREFIX_PATH=$(pwd)/../.local .. && ninja
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: No CI test for USE_ENCODING_LIB=OFF -> Add one if we want to keep that (plain) option.

- run:
name: Run tests (-DNOPUBKEY_IN_PRIVKEY=ON)
command: |
./scripts/runtests.sh -V
- run:
name: Run tests (-DNOPUBKEY_IN_PRIVKEY=ON, with encodings)
command: |
./scripts/runtests_encodings.sh -V
workflows:
version: 2.1
build:
Expand Down
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ if(${NOPUBKEY_IN_PRIVKEY})
else()
message(STATUS "Build will store public keys in PKCS#8 structures")
endif()
option(USE_ENCODING_LIB "Build with external encoding library for SPKI/PKCS#8 " ON)
if(${USE_ENCODING_LIB})
message(STATUS "Build will include external encoding library for SPKI/PKCS#8")
add_compile_definitions( USE_ENCODING_LIB )
else()
message(STATUS "Build will not include external encoding library for SPKI/PKCS#8")
endif()

include(CheckLibraryExists)
include(CheckFunctionExists)
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,34 @@ excludes all algorithms of the "Sphincs" family.
*Note*: By default, interoperability testing with oqs-openssl111 is no longer
performed by default but can be manually enabled in the script `scripts/runtests.sh`.

### Key Encoding

By setting environment variables, oqs-provider can be configured to encode keys (subjectPublicKey and and privateKey ASN.1 structures) according to IETF drafts:

| Environment Variable | Permissible values |
| --- | --- |
| `OQS_ENCODING_DILITHIUM2` | `draft-uni-qsckeys-dilithium-00/sk-pk` |
| `OQS_ENCODING_DILITHIUM3` | `draft-uni-qsckeys-dilithium-00/sk-pk` |
| `OQS_ENCODING_DILITHIUM5` | `draft-uni-qsckeys-dilithium-00/sk-pk` |
| `OQS_ENCODING_DILITHIUM2_AES` | `draft-uni-qsckeys-dilithium-00/sk-pk` |
| `OQS_ENCODING_DILITHIUM3_AES` | `draft-uni-qsckeys-dilithium-00/sk-pk` |
| `OQS_ENCODING_DILITHIUM5_AES` | `draft-uni-qsckeys-dilithium-00/sk-pk` |
| `OQS_ENCODING_FALCON512` | `draft-uni-qsckeys-falcon-00/sk-pk` |
| `OQS_ENCODING_FALCON1024` | `draft-uni-qsckeys-falcon-00/sk-pk` |
| `OQS_ENCODING_SPHINCSHARAKA128FROBUST` | `draft-uni-qsckeys-sphincsplus-00/sk-pk` |
| `OQS_ENCODING_SPHINCSHARAKA128FSIMPLE` | `draft-uni-qsckeys-sphincsplus-00/sk-pk` |
| `OQS_ENCODING_SPHINCSSHA256128FROBUST` | `draft-uni-qsckeys-sphincsplus-00/sk-pk` |
| `OQS_ENCODING_SPHINCSSHA256128SSIMPLE` | `draft-uni-qsckeys-sphincsplus-00/sk-pk` |
| `OQS_ENCODING_SPHINCSSHAKE256128FSIMPLE` | `draft-uni-qsckeys-sphincsplus-00/sk-pk` |

If no environment variable is set, or if an unknown value is set, the default is 'no' encoding, meaning that key serialization uses the 'raw' keys of the crypto implementations.

The test script `scripts/runtests_encodings.sh` (instead of `scripts/runtests.sh`) can be used for a test run with all supported encodings activated.

By setting `-DUSE_ENCODING_LIB=OFF` at compile-time, oqs-provider can be optionally compiled without support for the IETF drafts for key encodings. The default value is `ON`.

By setting `-DNOPUBKEY_IN_PRIVKEY` at compile-time, it can be further specified to omit explicitly serializing the public key in a `privateKey` structure. The default value is `OFF`.

Building on Windows
--------------------
The following steps have been tested on Windows 10 and 11 using MSYS2 MINGW64 and were successful. However, building with Visual Studio 2019 was unsuccessful (see [#47](https://github.com/open-quantum-safe/oqs-provider/issues/47)). Note that the process of building on Windows is considered experimental and may need further adjustments. Please report further issues to [#47](https://github.com/open-quantum-safe/oqs-provider/issues/47). Despite skipping the testing process, setting up a test server and client with post-quantum cryptography algorithms can still be accomplished.
Expand Down
11 changes: 7 additions & 4 deletions oqs-template/oqsprov/oqs_kmgmt.c/keymgmt_constructors.fragment
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
{% set count = namespace(val=-1) -%}
{% for sig in config['sigs'] %}
{%- for variant in sig['variants'] %}
{%- set count.val = count.val + 1 %}
static void *{{variant['name']}}_new_key(void *provctx)
{
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{variant['name']}}", KEY_TYPE_SIG, NULL, {{variant['security']}});
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{variant['name']}}", KEY_TYPE_SIG, NULL, {{variant['security']}}, {{ count.val }});
}

static void *{{variant['name']}}_gen_init(void *provctx, int selection)
{
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{variant['name']}}", 0, {{variant['security']}});
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{variant['name']}}", 0, {{variant['security']}}, {{ count.val }});
}

{%- for classical_alg in variant['mix_with'] %}
{%- set count.val = count.val + 1 %}
static void *{{ classical_alg['name'] }}_{{variant['name']}}_new_key(void *provctx)
{
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, NULL, {{variant['security']}});
return oqsx_key_new(PROV_OQS_LIBCTX_OF(provctx), {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, NULL, {{variant['security']}}, {{ count.val }});
}

static void *{{ classical_alg['name'] }}_{{variant['name']}}_gen_init(void *provctx, int selection)
{
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, {{variant['security']}});
return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{ classical_alg['name'] }}_{{variant['name']}}", KEY_TYPE_HYB_SIG, {{variant['security']}}, {{ count.val }});
}

{%- endfor -%}
Expand Down
2 changes: 1 addition & 1 deletion oqs-template/oqsprov/oqsprov.c/assign_sig_oids.fragment
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
{%- endfor %}
{%- endfor %}
#define OQS_OID_CNT {{ count.val*2 }}
static const char* oqs_oid_alg_list[OQS_OID_CNT] =
const char* oqs_oid_alg_list[OQS_OID_CNT] =
{

{%- for sig in config['sigs'] %}
Expand Down
12 changes: 12 additions & 0 deletions oqs-template/oqsprov/oqsprov.c/encoding_patching.fragment
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% set cnt = namespace(val=-1) %}
{%- for sig in config['sigs'] %}
{%- for variant in sig['variants'] %}
{%- set cnt.val = cnt.val + 1 %}
if (getenv("OQS_ENCODING_{{variant['name']|upper}}")) oqs_alg_encoding_list[{{ cnt.val }}] = getenv("OQS_ENCODING_{{variant['name']|upper}}");
{%- for classical_alg in variant['mix_with'] %}
{%- set cnt.val = cnt.val + 1 %}
if (getenv("OQS_ENCODING_{{ classical_alg['name']|upper }}_{{variant['name']|upper}}")) oqs_alg_encoding_list[{{ cnt.val }}] = getenv("OQS_ENCODING_{{ classical_alg['name']|upper }}_{{variant['name']|upper}}");
{%- endfor %}
{%- endfor %}
{%- endfor %}

21 changes: 21 additions & 0 deletions oqsprov/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ execute_process(
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (USE_ENCODING_LIB)
include(ExternalProject)
set(encoder_LIBRARY ${CMAKE_BINARY_DIR}/install/lib/${CMAKE_STATIC_LIBRARY_PREFIX}qsc_key_encoder${CMAKE_STATIC_LIBRARY_SUFFIX})
set(encoder_LIBRARY_INCLUDE ${CMAKE_BINARY_DIR}/install/include)
ExternalProject_Add(encoder
GIT_REPOSITORY https://github.com/Quantum-Safe-Collaboration/qsc-key-rfc.git
GIT_TAG main
SOURCE_SUBDIR qsc-key-encoder
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/install -DCMAKE_BUILD_TYPE=Release
BUILD_BYPRODUCTS ${encoder_LIBRARY}
)
add_library(qsc_key_encoder STATIC IMPORTED)
set_target_properties(qsc_key_encoder PROPERTIES IMPORTED_LOCATION ${encoder_LIBRARY})
endif()
add_definitions(-DOQSPROVIDER_VERSION_TEXT="${OQSPROVIDER_VERSION_TEXT}")
message(STATUS "Building commit ${GIT_COMMIT_HASH} in ${CMAKE_SOURCE_DIR}")
add_definitions(-DOQS_PROVIDER_COMMIT=" \(${GIT_COMMIT_HASH}\)")
Expand All @@ -19,6 +33,9 @@ set(PROVIDER_HEADER_FILES
oqs_prov.h oqs_endecoder_local.h
)
add_library(oqsprovider SHARED ${PROVIDER_SOURCE_FILES})
if (USE_ENCODING_LIB)
add_dependencies(oqsprovider encoder)
endif()
set_target_properties(oqsprovider
PROPERTIES
PREFIX ""
Expand All @@ -30,6 +47,10 @@ set_target_properties(oqsprovider
# For Windows DLLs
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
target_link_libraries(oqsprovider OQS::oqs ${OPENSSL_CRYPTO_LIBRARY})
if (USE_ENCODING_LIB)
target_link_libraries(oqsprovider qsc_key_encoder)
target_include_directories(oqsprovider PRIVATE ${encoder_LIBRARY_INCLUDE})
endif()
install(TARGETS oqsprovider
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_LIBDIR}")
Expand Down
76 changes: 58 additions & 18 deletions oqsprov/oqs_encode_key2any.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,22 +504,40 @@ static int oqsx_spki_pub_to_der(const void *vxkey, unsigned char **pder)
{
const OQSX_KEY *oqsxkey = vxkey;
unsigned char *keyblob;
int ret = 0;

OQS_ENC_PRINTF("OQS ENC provider: oqsx_spki_pub_to_der called\n");

if (oqsxkey == NULL) {
if (oqsxkey == NULL || oqsxkey->pubkey == NULL) {
ERR_raise(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}

keyblob = OPENSSL_memdup(oqsxkey->pubkey, oqsxkey->pubkeylen);
if (keyblob == NULL) {
ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE);
return 0;
#ifdef USE_ENCODING_LIB
if (oqsxkey->oqsx_encoding_ctx.encoding_ctx != NULL && oqsxkey->oqsx_encoding_ctx.encoding_impl != NULL) {
unsigned char *buf;
int buflen;
int ret = 0;
const OQSX_ENCODING_CTX* encoding_ctx = &oqsxkey->oqsx_encoding_ctx;
buflen = encoding_ctx->encoding_impl->crypto_publickeybytes;

buf = OPENSSL_secure_zalloc(buflen);
ret = qsc_encode(encoding_ctx->encoding_ctx, encoding_ctx->encoding_impl, oqsxkey->pubkey, &buf, 0, 0, 1);
if (ret != QSC_ENC_OK) return -1;

*pder = buf;
return buflen;
} else {
#endif
keyblob = OPENSSL_memdup(oqsxkey->pubkey, oqsxkey->pubkeylen);
if (keyblob == NULL) {
ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE);
return 0;
}
*pder = keyblob;
return oqsxkey->pubkeylen;
#ifdef USE_ENCODING_LIB
}

*pder = keyblob;
return oqsxkey->pubkeylen;
#endif
}

static int oqsx_pki_priv_to_der(const void *vxkey, unsigned char **pder)
Expand Down Expand Up @@ -557,17 +575,39 @@ static int oqsx_pki_priv_to_der(const void *vxkey, unsigned char **pder)
}
privkeylen -= (oqsxkey->evp_info->length_private_key - actualprivkeylen);
}
#ifdef USE_ENCODING_LIB
if (oqsxkey->oqsx_encoding_ctx.encoding_ctx != NULL && oqsxkey->oqsx_encoding_ctx.encoding_impl != NULL) {
const OQSX_ENCODING_CTX* encoding_ctx = &oqsxkey->oqsx_encoding_ctx;
int ret = 0;
#ifdef NOPUBKEY_IN_PRIVKEY
int withoptional = (encoding_ctx->encoding_ctx->raw_private_key_encodes_public_key ? 1 : 0);
#else
int withoptional = 1;
#endif
buflen = (withoptional ? encoding_ctx->encoding_impl->crypto_secretkeybytes :
encoding_ctx->encoding_impl->crypto_secretkeybytes_nooptional);
buf = OPENSSL_secure_zalloc(buflen);

ret = qsc_encode(encoding_ctx->encoding_ctx, encoding_ctx->encoding_impl,
oqsxkey->comp_pubkey[oqsxkey->numkeys-1], 0,
oqsxkey->privkey, &buf, withoptional);
if (ret != QSC_ENC_OK) return -1;
} else {
#endif
#ifdef NOPUBKEY_IN_PRIVKEY
buflen = privkeylen;
buf = OPENSSL_secure_malloc(buflen);
OQS_ENC_PRINTF2("OQS ENC provider: saving privkey of length %d\n", buflen);
memcpy(buf, oqsxkey->privkey, privkeylen);
buflen = privkeylen;
buf = OPENSSL_secure_malloc(buflen);
OQS_ENC_PRINTF2("OQS ENC provider: saving privkey of length %d\n", buflen);
memcpy(buf, oqsxkey->privkey, privkeylen);
#else
buflen = privkeylen+oqsx_key_get_oqs_public_key_len(oqsxkey);
buf = OPENSSL_secure_malloc(buflen);
OQS_ENC_PRINTF2("OQS ENC provider: saving priv+pubkey of length %d\n", buflen);
memcpy(buf, oqsxkey->privkey, privkeylen);
memcpy(buf+privkeylen, oqsxkey->comp_pubkey[oqsxkey->numkeys-1], oqsx_key_get_oqs_public_key_len(oqsxkey));
buflen = privkeylen+oqsx_key_get_oqs_public_key_len(oqsxkey);
buf = OPENSSL_secure_malloc(buflen);
OQS_ENC_PRINTF2("OQS ENC provider: saving priv+pubkey of length %d\n", buflen);
memcpy(buf, oqsxkey->privkey, privkeylen);
memcpy(buf+privkeylen, oqsxkey->comp_pubkey[oqsxkey->numkeys-1], oqsx_key_get_oqs_public_key_len(oqsxkey));
#endif
#ifdef USE_ENCODING_LIB
}
#endif

oct.data = buf;
Expand Down
Loading