Skip to content

Commit

Permalink
Migrate Kyber 512 to EVP KEM API (#3853)
Browse files Browse the repository at this point in the history
New usage is based on [the KEM API design document][1] and [header][2].
Now that we're on a stable KEM API, we remove the
S2N_AWSLC_KYBER_UNSTABLE build flag and always use the linked
libcrypto's Kyber implementation if available. This flag wasn't
previously specified in any of our CI scripts, meaning that
AWS-LC-backed kyber was previously uncovered in s2n's CI. This commit
ensures that coverage and updates the PQ KEM unit test to asserts that
if (non-FIPS) AWS-LC is used as the backing libcrypto, it has the new
Kyber 512 KEM API available.

[1]: https://github.com/aws/aws-lc/blob/main/crypto/kem/README.md
[2]: https://github.com/aws/aws-lc/blob/92c56fbc15f9bb43c4ff062c6c02f7991fd417f6/include/openssl/evp.h#L880

Check for other pre-processor symbol from AWS-LC
  • Loading branch information
WillChilds-Klein authored Mar 16, 2023
1 parent 63870f4 commit 10ec83a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 22 deletions.
9 changes: 4 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ option(S2N_NO_PQ "Disables all Post Quantum Crypto code. You likely want this
for older compilers or uncommon platforms." OFF)
option(S2N_NO_PQ_ASM "Turns off the ASM for PQ Crypto even if it's available for the toolchain.
You likely want this on older compilers." OFF)
option(S2N_AWSLC_KYBER_UNSTABLE "Prefer the AWS-LC provided PQ implementation." OFF)
option(SEARCH_LIBCRYPTO "Set this if you want to let S2N search libcrypto for you,
otherwise a crypto target needs to be defined." ON)
option(UNSAFE_TREAT_WARNINGS_AS_ERRORS "Compiler warnings are treated as errors. Warnings may
Expand Down Expand Up @@ -445,16 +444,16 @@ if (LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX)
target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX)
endif()

# Determine if Kyber512 implementation from AWS-LC is available
# Determine if KEM Kyber512 implementation from AWS-LC is available
try_compile(
LIBCRYPTO_SUPPORTS_EVP_KYBER_512
LIBCRYPTO_SUPPORTS_EVP_KEM_KYBER_512
${CMAKE_BINARY_DIR}
SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/evp_kyber_512.c"
SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/evp_kem_kyber_512.c"
LINK_LIBRARIES ${LINK_LIB} ${OS_LIBS}
COMPILE_DEFINITIONS "-Werror"
)

if(S2N_AWSLC_KYBER_UNSTABLE AND LIBCRYPTO_SUPPORTS_EVP_KYBER_512)
if(LIBCRYPTO_SUPPORTS_EVP_KEM_KYBER_512)
target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_LIBCRYPTO_SUPPORTS_KYBER512)
endif()

Expand Down
36 changes: 21 additions & 15 deletions pq-crypto/s2n_kyber_512_evp.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,38 @@

#include "error/s2n_errno.h"
#include "tls/s2n_kem.h"
#include "utils/s2n_safety.h"
#include "utils/s2n_safety_macros.h"

#if defined(S2N_LIBCRYPTO_SUPPORTS_KYBER512)
int s2n_kyber_512_evp_generate_keypair(uint8_t *public_key, uint8_t *private_key) {
EVP_PKEY_CTX *kyber_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_KYBER512, NULL);
#if defined(S2N_LIBCRYPTO_SUPPORTS_KYBER512) && !defined(S2N_NO_PQ)

DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY *, EVP_PKEY_free);
DEFINE_POINTER_CLEANUP_FUNC(EVP_PKEY_CTX *, EVP_PKEY_CTX_free);

int s2n_kyber_512_evp_generate_keypair(uint8_t *public_key, uint8_t *secret_key) {
DEFER_CLEANUP(EVP_PKEY_CTX *kyber_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, NULL), EVP_PKEY_CTX_free_pointer);
POSIX_GUARD_PTR(kyber_pkey_ctx);
POSIX_GUARD_OSSL(EVP_PKEY_CTX_kem_set_params(kyber_pkey_ctx, NID_KYBER512_R3), S2N_ERR_PQ_CRYPTO);
POSIX_GUARD_OSSL(EVP_PKEY_keygen_init(kyber_pkey_ctx), S2N_ERR_PQ_CRYPTO);

EVP_PKEY *kyber_pkey = NULL;
DEFER_CLEANUP(EVP_PKEY *kyber_pkey = NULL, EVP_PKEY_free_pointer);
POSIX_GUARD_OSSL(EVP_PKEY_keygen(kyber_pkey_ctx, &kyber_pkey), S2N_ERR_PQ_CRYPTO);

size_t public_key_size = S2N_KYBER_512_R3_PUBLIC_KEY_BYTES;
size_t private_key_size = S2N_KYBER_512_R3_SECRET_KEY_BYTES;
size_t secret_key_size = S2N_KYBER_512_R3_SECRET_KEY_BYTES;
POSIX_GUARD_OSSL(EVP_PKEY_get_raw_public_key(kyber_pkey, public_key, &public_key_size), S2N_ERR_PQ_CRYPTO);
POSIX_GUARD_OSSL(EVP_PKEY_get_raw_private_key(kyber_pkey, private_key, &private_key_size), S2N_ERR_PQ_CRYPTO);
POSIX_GUARD_OSSL(EVP_PKEY_get_raw_private_key(kyber_pkey, secret_key, &secret_key_size), S2N_ERR_PQ_CRYPTO);

return S2N_SUCCESS;
}

int s2n_kyber_512_evp_encapsulate(uint8_t *ciphertext, uint8_t *shared_secret,
const uint8_t *public_key) {
size_t public_key_size = S2N_KYBER_512_R3_PUBLIC_KEY_BYTES;
EVP_PKEY *kyber_pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_KYBER512, NULL, public_key, public_key_size);
DEFER_CLEANUP(EVP_PKEY *kyber_pkey = EVP_PKEY_kem_new_raw_public_key(NID_KYBER512_R3, public_key, public_key_size), EVP_PKEY_free_pointer);
POSIX_GUARD_PTR(kyber_pkey);

EVP_PKEY_CTX *kyber_pkey_ctx = EVP_PKEY_CTX_new(kyber_pkey, NULL);
DEFER_CLEANUP(EVP_PKEY_CTX *kyber_pkey_ctx = EVP_PKEY_CTX_new(kyber_pkey, NULL), EVP_PKEY_CTX_free_pointer);
POSIX_GUARD_PTR(kyber_pkey_ctx);

size_t cipher_text_size = S2N_KYBER_512_R3_CIPHERTEXT_BYTES;
Expand All @@ -56,21 +62,21 @@ int s2n_kyber_512_evp_encapsulate(uint8_t *ciphertext, uint8_t *shared_secret,
}

int s2n_kyber_512_evp_decapsulate(uint8_t *shared_secret, const uint8_t *ciphertext,
const uint8_t *private_key) {
size_t private_key_size = S2N_KYBER_512_R3_SECRET_KEY_BYTES;
EVP_PKEY *kyber_pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_KYBER512, NULL, private_key, private_key_size);
const uint8_t *secret_key) {
size_t secret_key_size = S2N_KYBER_512_R3_SECRET_KEY_BYTES;
DEFER_CLEANUP(EVP_PKEY *kyber_pkey = EVP_PKEY_kem_new_raw_secret_key(NID_KYBER512_R3, secret_key, secret_key_size), EVP_PKEY_free_pointer);
POSIX_GUARD_PTR(kyber_pkey);

EVP_PKEY_CTX *kyber_pkey_ctx = EVP_PKEY_CTX_new(kyber_pkey, NULL);
DEFER_CLEANUP(EVP_PKEY_CTX *kyber_pkey_ctx = EVP_PKEY_CTX_new(kyber_pkey, NULL), EVP_PKEY_CTX_free_pointer);
POSIX_GUARD_PTR(kyber_pkey_ctx);

size_t shared_secret_size = S2N_KYBER_512_R3_SHARED_SECRET_BYTES;
POSIX_GUARD_OSSL(EVP_PKEY_decapsulate(kyber_pkey_ctx, shared_secret, &shared_secret_size, (uint8_t *) ciphertext,
S2N_KYBER_512_R3_CIPHERTEXT_BYTES), S2N_ERR_PQ_CRYPTO);
S2N_KYBER_512_R3_CIPHERTEXT_BYTES), S2N_ERR_PQ_CRYPTO);
return S2N_SUCCESS;
}
#else
int s2n_kyber_512_evp_generate_keypair(OUT uint8_t *public_key, OUT uint8_t *private_key) {
int s2n_kyber_512_evp_generate_keypair(OUT uint8_t *public_key, OUT uint8_t *secret_key) {
POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
}

Expand All @@ -80,7 +86,7 @@ int s2n_kyber_512_evp_encapsulate(OUT uint8_t *ciphertext, OUT uint8_t *shared_s
}

int s2n_kyber_512_evp_decapsulate(OUT uint8_t *shared_secret, IN const uint8_t *ciphertext,
IN const uint8_t *private_key) {
IN const uint8_t *secret_key) {
POSIX_BAIL(S2N_ERR_UNIMPLEMENTED);
}
#endif
6 changes: 6 additions & 0 deletions s2n.mk
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ ifeq ($(TRY_EVP_MD_CTX_SET_PKEY_CTX), 0)
DEFAULT_CFLAGS += -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX
endif

# Determine if the Kyber 512 KEM API is available in libcrypto
TRY_LIBCRYPTO_SUPPORTS_KYBER512 := $(call try_compile,$(S2N_ROOT)/tests/features/evp_kem_kyber_512.c)
ifeq ($(TRY_LIBCRYPTO_SUPPORTS_KYBER512), 0)
DEFAULT_CFLAGS += -DS2N_LIBCRYPTO_SUPPORTS_KYBER512
endif

# Determine if madvise() is available
TRY_COMPILE_MADVISE := $(call try_compile,$(S2N_ROOT)/tests/features/madvise.c)
ifeq ($(TRY_COMPILE_MADVISE), 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,17 @@
*/

#include <openssl/evp.h>
#include <openssl/nid.h>

int main() {
EVP_PKEY_CTX *kyber_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_KYBER512, NULL);
return 0;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, NULL);
if (ctx == NULL) {
return 1;
}
if (!EVP_PKEY_CTX_kem_set_params(ctx, NID_KYBER512_R3)) {
EVP_PKEY_CTX_free(ctx);
return 1;
}
EVP_PKEY_CTX_free(ctx);
return 0;
}
17 changes: 17 additions & 0 deletions tests/unit/s2n_pq_kem_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
* permissions and limitations under the License.
*/

#include <openssl/crypto.h>

#include "crypto/s2n_fips.h"
#include "crypto/s2n_openssl.h"
#include "pq-crypto/s2n_pq.h"
#include "s2n_test.h"
#include "tests/testlib/s2n_testlib.h"
Expand Down Expand Up @@ -50,6 +54,19 @@ int main()
{
BEGIN_TEST();

#if defined(OPENSSL_IS_AWSLC) && defined(AWS_LC_API_VERSION)
const unsigned long lc_vers = awslc_api_version_num();
#else
const unsigned long lc_vers = SSLeay();
#endif

/* If using non-FIPS AWS-LC >= v1.4.0 (API vers. 20), expect Kyber512 KEM from AWS-LC */
if (s2n_libcrypto_is_awslc() && lc_vers >= 20 && !s2n_libcrypto_is_fips()) {
EXPECT_TRUE(s2n_libcrypto_supports_kyber_512());
} else {
EXPECT_FALSE(s2n_libcrypto_supports_kyber_512());
}

for (size_t i = 0; i < s2n_array_len(test_vectors); i++) {
const struct s2n_kem_test_vector vector = test_vectors[i];
const struct s2n_kem *kem = vector.kem;
Expand Down

0 comments on commit 10ec83a

Please sign in to comment.