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

Make portable builds work across OpenSSL 1.0.2/1.1.1/3.0 #51155

Merged
merged 2 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ include_directories(${OPENSSL_INCLUDE_DIR})

set(NATIVECRYPTO_SOURCES
apibridge.c
apibridge_30.c
openssl.c
pal_asn1.c
pal_bignum.c
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "opensslshim.h"
#include "pal_crypto_types.h"
#include "pal_types.h"

#include "../Common/pal_safecrt.h"
#include <assert.h>

#if defined NEED_OPENSSL_1_0 || defined NEED_OPENSSL_1_1

#include "apibridge_30.h"

// 1.0 and 1.1 agree on the values of the EVP_PKEY_ values, but some of them changed in 3.0.
// If we're running on 3.0 we already call the real methods, not these fallbacks, so we need to always use
// the 1.0/1.1 values here.

// These values are in common.
c_static_assert(EVP_PKEY_CTRL_MD == 1);
c_static_assert(EVP_PKEY_CTRL_RSA_KEYGEN_BITS == 0x1003);
c_static_assert(EVP_PKEY_CTRL_RSA_OAEP_MD == 0x1009);
c_static_assert(EVP_PKEY_CTRL_RSA_PADDING == 0x1001);
c_static_assert(EVP_PKEY_CTRL_RSA_PSS_SALTLEN == 0x1002);
c_static_assert(EVP_PKEY_OP_KEYGEN == (1 << 2));
c_static_assert(EVP_PKEY_RSA == 6);

#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM

c_static_assert(EVP_PKEY_OP_SIGN == (1 << 3));
c_static_assert(EVP_PKEY_OP_VERIFY == (1 << 4));
c_static_assert(EVP_PKEY_OP_TYPE_CRYPT == ((1 << 8) | (1 << 9)));
c_static_assert(EVP_PKEY_OP_TYPE_SIG == 0xF8);

#else

#undef EVP_PKEY_OP_SIGN
#define EVP_PKEY_OP_SIGN (1 << 3)
#undef EVP_PKEY_OP_VERIFY
#define EVP_PKEY_OP_VERIFY (1 << 4)
#undef EVP_PKEY_OP_TYPE_CRYPT
#define EVP_PKEY_OP_TYPE_CRYPT ((1 << 8) | (1 << 9))
#undef EVP_PKEY_OP_TYPE_SIG
#define EVP_PKEY_OP_TYPE_SIG 0xF8 // OP_SIGN | OP_VERIFY | OP_VERIFYRECOVER | OP_SIGNCTX | OP_VERIFYCTX

#endif

int local_EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits)
{
return RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL);
}

int local_EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md)
{
// set_rsa_oaep_md doesn't route through RSA_pkey_ctx_ctrl n 1.1, unlike the other set_rsa operations.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void*)md);
#pragma clang diagnostic pop
}

int local_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode)
{
return RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad_mode, NULL);
}

int local_EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen)
{
return RSA_pkey_ctx_ctrl(
ctx, (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY), EVP_PKEY_CTRL_RSA_PSS_SALTLEN, saltlen, NULL);
}

int local_EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md)
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-qual"
return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, (void*)md);
#pragma clang diagnostic pop
}

#endif // defined NEED_OPENSSL_1_0 || defined NEED_OPENSSL_1_1

#ifdef NEED_OPENSSL_3_0

#include "apibridge_30_rev.h"

void local_ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line)
{
// In portable builds, ensure that we found the 3.0 error reporting functions.
// In non-portable builds, this is just assert(true), but then we call the functions,
// so the compiler ensures they're there anyways.
assert(API_EXISTS(ERR_new) && API_EXISTS(ERR_set_debug) && API_EXISTS(ERR_set_error));
ERR_new();

// ERR_set_debug saves only the pointer, not the value, as it expects constants.
// So just ignore the legacy numeric code, and use the 3.0 "Uh, I don't know"
// function name.
(void)func;
ERR_set_debug(file, line, "(unknown function)");

ERR_set_error(lib, reason, NULL);
}

#endif // defined NEED_OPENSSL_3_0
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Functions based on OpenSSL 3.0 API, used when building against/running with older versions.

#pragma once
#include "pal_types.h"

int local_EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits);
int local_EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md);
int local_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode);
int local_EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen);
int local_EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Functions based on OpenSSL 3.0 API, used when building against/running with older versions.

#pragma once
#include "pal_types.h"

// For 3.0 to behave like previous versions.
void local_ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line);
Original file line number Diff line number Diff line change
Expand Up @@ -1260,7 +1260,7 @@ static int32_t EnsureOpenSsl10Initialized()
}
#endif // NEED_OPENSSL_1_0 */

#ifdef NEED_OPENSSL_1_1
#if defined NEED_OPENSSL_1_1 || defined NEED_OPENSSL_3_0

// Only defined in OpenSSL 1.1.1+, has no effect on 1.1.0.
#ifndef OPENSSL_INIT_NO_ATEXIT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

// Define pointers to all the used OpenSSL functions
#define REQUIRED_FUNCTION(fn) TYPEOF(fn) fn##_ptr;
#define NEW_REQUIRED_FUNCTION(fn) TYPEOF(fn) fn##_ptr;
#define REQUIRED_FUNCTION_110(fn) TYPEOF(fn) fn##_ptr;
#define LIGHTUP_FUNCTION(fn) TYPEOF(fn) fn##_ptr;
#define FALLBACK_FUNCTION(fn) TYPEOF(fn) fn##_ptr;
#define RENAMED_FUNCTION(fn,oldfn) TYPEOF(fn) fn##_ptr;
Expand All @@ -23,7 +23,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#undef RENAMED_FUNCTION
#undef FALLBACK_FUNCTION
#undef LIGHTUP_FUNCTION
#undef NEW_REQUIRED_FUNCTION
#undef REQUIRED_FUNCTION_110
#undef REQUIRED_FUNCTION

// x.x.x, considering the max number of decimal digits for each component
Expand Down Expand Up @@ -78,7 +78,12 @@ static bool OpenLibrary()

if (libssl == NULL)
{
// Prefer OpenSSL 1.1.x
// Prefer OpenSSL 3.x
DlOpen(MAKELIB("3"));
}

if (libssl == NULL)
{
DlOpen(MAKELIB("1.1"));
}

Expand Down Expand Up @@ -138,7 +143,7 @@ void InitializeOpenSSLShim(void)
#define REQUIRED_FUNCTION(fn) \
if (!(fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); }

#define NEW_REQUIRED_FUNCTION(fn) \
#define REQUIRED_FUNCTION_110(fn) \
if (!v1_0_sentinel && !(fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); }

#define LIGHTUP_FUNCTION(fn) \
Expand All @@ -148,8 +153,8 @@ void InitializeOpenSSLShim(void)
if (!(fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #fn)))) { fn##_ptr = (TYPEOF(fn))local_##fn; }

#define RENAMED_FUNCTION(fn,oldfn) \
if (!v1_0_sentinel && !(fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } \
if (v1_0_sentinel && !(fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #oldfn)))) { fprintf(stderr, "Cannot get required symbol " #oldfn " from libssl\n"); abort(); }
fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #fn));\
if (!fn##_ptr && !(fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #oldfn)))) { fprintf(stderr, "Cannot get required symbol " #oldfn " from libssl\n"); abort(); }

#define LEGACY_FUNCTION(fn) \
if (v1_0_sentinel && !(fn##_ptr = (TYPEOF(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); }
Expand All @@ -159,6 +164,16 @@ void InitializeOpenSSLShim(void)
#undef RENAMED_FUNCTION
#undef FALLBACK_FUNCTION
#undef LIGHTUP_FUNCTION
#undef NEW_REQUIRED_FUNCTION
#undef REQUIRED_FUNCTION_110
#undef REQUIRED_FUNCTION

// Sanity check that we have at least one functioning way of reporting errors.
if (ERR_put_error_ptr == &local_ERR_put_error)
{
if (ERR_new_ptr == NULL || ERR_set_debug_ptr == NULL || ERR_set_error_ptr == NULL)
{
fprintf(stderr, "Cannot determine the error reporting routine from libssl\n");
abort();
}
}
}
Loading