Skip to content

Commit

Permalink
Merge pull request #96 from ColeBollig/Openssl_3_0-update
Browse files Browse the repository at this point in the history
Openssl 3 0 update
  • Loading branch information
djw8605 authored Oct 14, 2022
2 parents 66f1a76 + 9ff3770 commit 4916492
Show file tree
Hide file tree
Showing 89 changed files with 33,764 additions and 1,587 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ccpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ env:
jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
external-gtest: [ YES, NO ]
os: [ ubuntu-latest, ubuntu-22.04 ]

name: Build with external_gtest=${{ matrix.external-gtest }}
runs-on: ${{ matrix.os }}
name: Build with external_gtest=${{ matrix.external-gtest }} on ${{ matrix.os }}

steps:
- uses: actions/checkout@v1
Expand Down
7 changes: 0 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ project( scitokens-cpp

option( SCITOKENS_BUILD_UNITTESTS "Build the scitokens-cpp unit tests" OFF )
option( SCITOKENS_EXTERNAL_GTEST "Use an external/pre-installed copy of GTest" OFF )
option( SCITOKENS_WARNINGS_ARE_ERRORS "Turn compiler warnings into build errors" OFF)

set( CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}" )

Expand Down Expand Up @@ -39,7 +38,6 @@ endif()

add_library(SciTokens SHARED src/scitokens.cpp src/scitokens_internal.cpp src/scitokens_cache.cpp)
target_compile_features(SciTokens PUBLIC cxx_std_11) # Use at least C++11 for building and when linking to scitokens
target_compile_options(SciTokens PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall $<$<BOOL:${SCITOKENS_WARNINGS_ARE_ERRORS}>:-Werror>>)
target_include_directories(SciTokens PUBLIC ${JWT_CPP_INCLUDES} "${PROJECT_SOURCE_DIR}/src" PRIVATE ${CURL_INCLUDES} ${OPENSSL_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS} ${SQLITE_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS})

target_link_libraries(SciTokens PUBLIC ${OPENSSL_LIBRARIES} ${LIBCRYPTO_LIBRARIES} ${CURL_LIBRARIES} ${SQLITE_LIBRARIES} ${UUID_LIBRARIES})
Expand All @@ -57,23 +55,18 @@ add_executable(scitokens-test src/test.cpp)
#target_include_directories(scitokens-test PRIVATE "${PROJECT_SOURCE_DIR}" ${JWT_CPP_INCLUDES} ${CURL_INCLUDES} ${OPENSSL_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS} ${SQLITE_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS})
target_include_directories(scitokens-test PRIVATE "${PROJECT_SOURCE_DIR}" ${JWT_CPP_INCLUDES} ${LIBCRYPTO_INCLUDE_DIRS})
target_link_libraries(scitokens-test SciTokens)
target_compile_options(scitokens-test PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall $<$<BOOL:${SCITOKENS_WARNINGS_ARE_ERRORS}>:-Werror>>)

add_executable(scitokens-verify src/verify.cpp)
target_link_libraries(scitokens-verify SciTokens)
target_compile_options(scitokens-verify PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall $<$<BOOL:${SCITOKENS_WARNINGS_ARE_ERRORS}>:-Werror>>)

add_executable(scitokens-test-access src/test_access.cpp)
target_link_libraries(scitokens-test-access SciTokens)
target_compile_options(scitokens-test-access PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall $<$<BOOL:${SCITOKENS_WARNINGS_ARE_ERRORS}>:-Werror>>)

add_executable(scitokens-list-access src/list_access.cpp)
target_link_libraries(scitokens-list-access SciTokens)
target_compile_options(scitokens-list-access PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall $<$<BOOL:${SCITOKENS_WARNINGS_ARE_ERRORS}>:-Werror>>)

add_executable(scitokens-create src/create.cpp)
target_link_libraries(scitokens-create SciTokens)
target_compile_options(scitokens-create PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall $<$<BOOL:${SCITOKENS_WARNINGS_ARE_ERRORS}>:-Werror>>)

get_directory_property(TARGETS BUILDSYSTEM_TARGETS)
install(
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Building

To build the `scitokens-cpp` library, the following dependencies are needed:

- [jwt-cpp](https://github.com/Thalhammer/jwt-cpp): A header-only C++ library for manipulating
- [jwt-cpp] v0.5.0 or later (https://github.com/Thalhammer/jwt-cpp): A header-only C++ library for manipulating
JWTs.
- OpenSSL 1.0 or later.
- `sqlite3`
Expand Down
161 changes: 141 additions & 20 deletions src/scitokens_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
#include <openssl/bn.h>
#include <openssl/ec.h>

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/evp.h>
#include <openssl/param_build.h>
#endif
#define EC_NAME NID_X9_62_prime256v1

#include "scitokens_internal.h"

using namespace scitokens;
Expand Down Expand Up @@ -243,8 +249,60 @@ std::string
es256_from_coords(const std::string &x_str, const std::string &y_str) {
auto x_decode = b64url_decode_nopadding(x_str);
auto y_decode = b64url_decode_nopadding(y_str);
std::unique_ptr<BIO, decltype(&BIO_free_all)> pubkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
std::unique_ptr<BIGNUM, decltype(&BN_free)> x_bignum(BN_bin2bn(reinterpret_cast<const unsigned char *>(x_decode.c_str()), x_decode.size(), nullptr), BN_free);
std::unique_ptr<BIGNUM, decltype(&BN_free)> y_bignum(BN_bin2bn(reinterpret_cast<const unsigned char *>(y_decode.c_str()), y_decode.size(), nullptr), BN_free);

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
unsigned char *buf;
OSSL_PARAM *params;
std::unique_ptr<EC_GROUP, decltype(&EC_GROUP_free)> ec_group(EC_GROUP_new_by_curve_name(EC_NAME),EC_GROUP_free);
if (!ec_group.get()) {
throw UnsupportedKeyException("Unable to get OpenSSL EC group");
}

std::unique_ptr<EC_POINT, decltype(&EC_POINT_free)> Q_point(EC_POINT_new(ec_group.get()), EC_POINT_free);
if (!Q_point.get()) {
throw UnsupportedKeyException("Unable to allocate new EC point");
}

if (!EC_POINT_set_affine_coordinates(ec_group.get(), Q_point.get(), x_bignum.get(), y_bignum.get(), NULL)) {
throw UnsupportedKeyException("Invalid elliptic curve point in key");
}

size_t out_len = EC_POINT_point2buf(ec_group.get(), Q_point.get(),POINT_CONVERSION_UNCOMPRESSED,&buf,NULL);
if (out_len == 0) {
throw UnsupportedKeyException("Failed to convert EC point to octet base buffer");
}

std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)> param_build(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
if (!param_build.get()
|| !OSSL_PARAM_BLD_push_utf8_string(param_build.get(),"group","prime256v1",0)
|| !OSSL_PARAM_BLD_push_octet_string(param_build.get(),"pub",buf,out_len)
|| (params = OSSL_PARAM_BLD_to_param(param_build.get())) == NULL) {
throw UnsupportedKeyException("Failed to build EC public key parameters");
}

EVP_PKEY *pkey = NULL;
std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> ec_ctx(EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL), EVP_PKEY_CTX_free);
if (!ec_ctx.get()) {
throw UnsupportedKeyException("Failed to set EC PKEY context");
}

if (EVP_PKEY_fromdata_init(ec_ctx.get()) <= 0
|| EVP_PKEY_fromdata(ec_ctx.get(),&pkey,EVP_PKEY_PUBLIC_KEY,params) <= 0
|| pkey == NULL) {
throw UnsupportedKeyException("Failed to set the EC public key");
}

std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), EC_KEY_free);
if (PEM_write_bio_PUBKEY(pubkey_bio.get(), pkey) == 0) {
throw UnsupportedKeyException("Failed to serialize EC public key");
}
EVP_PKEY_free(pkey);
OSSL_PARAM_free(params);
OPENSSL_free(buf);
#else
std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> ec(EC_KEY_new_by_curve_name(EC_NAME), EC_KEY_free);
if (!ec.get()) {
throw UnsupportedKeyException("OpenSSL does not support the P-256 curve");
}
Expand All @@ -258,8 +316,7 @@ es256_from_coords(const std::string &x_str, const std::string &y_str) {
if (!Q_point.get()) {
throw UnsupportedKeyException("Unable to allocate new EC point");
}
std::unique_ptr<BIGNUM, decltype(&BN_free)> x_bignum(BN_bin2bn(reinterpret_cast<const unsigned char *>(x_decode.c_str()), x_decode.size(), nullptr), BN_free);
std::unique_ptr<BIGNUM, decltype(&BN_free)> y_bignum(BN_bin2bn(reinterpret_cast<const unsigned char *>(y_decode.c_str()), y_decode.size(), nullptr), BN_free);

if (EC_POINT_set_affine_coordinates_GFp(params, Q_point.get(), x_bignum.get(), y_bignum.get(), NULL) != 1) {
throw UnsupportedKeyException("Invalid elliptic curve point in key");
}
Expand All @@ -268,10 +325,10 @@ es256_from_coords(const std::string &x_str, const std::string &y_str) {
throw UnsupportedKeyException("Unable to set the EC public key");
}

std::unique_ptr<BIO, decltype(&BIO_free_all)> pubkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
if (PEM_write_bio_EC_PUBKEY(pubkey_bio.get(), ec.get()) == 0) {
if (PEM_write_bio_EC_PUBKEY(pubkey_bio.get(), ec.get()) == 0) {
throw UnsupportedKeyException("Failed to serialize EC public key");
}
#endif

char *mem_data;
size_t mem_len = BIO_get_mem_data(pubkey_bio.get(), &mem_data);
Expand All @@ -284,29 +341,57 @@ std::string
rs256_from_coords(const std::string &e_str, const std::string &n_str) {
auto e_decode = b64url_decode_nopadding(e_str);
auto n_decode = b64url_decode_nopadding(n_str);
std::unique_ptr<BIO, decltype(&BIO_free_all)> pubkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
std::unique_ptr<BIGNUM, decltype(&BN_free)> e_bignum(BN_bin2bn(reinterpret_cast<const unsigned char *>(e_decode.c_str()), e_decode.size(), nullptr), BN_free);
std::unique_ptr<BIGNUM, decltype(&BN_free)> n_bignum(BN_bin2bn(reinterpret_cast<const unsigned char *>(n_decode.c_str()), n_decode.size(), nullptr), BN_free);

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
OSSL_PARAM *params;
std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)> rsa_ctx(EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL), EVP_PKEY_CTX_free);
if (!rsa_ctx.get()) {
throw UnsupportedKeyException("Failed to set RSA PKEY context");
}

std::unique_ptr<RSA, decltype(&RSA_free)> rsa(RSA_new(), RSA_free);
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
rsa->e = e_bignum.get();
rsa->n = n_bignum.get();
rsa->d = nullptr;
#else
RSA_set0_key(rsa.get(), n_bignum.get(), e_bignum.get(), nullptr);
#endif
e_bignum.release();
n_bignum.release();
std::unique_ptr<OSSL_PARAM_BLD, decltype(&OSSL_PARAM_BLD_free)> param_build(OSSL_PARAM_BLD_new(), OSSL_PARAM_BLD_free);
if (!param_build.get()
|| !OSSL_PARAM_BLD_push_BN_pad(param_build.get(),"e",e_bignum.get(),BN_num_bytes(e_bignum.get()))
|| !OSSL_PARAM_BLD_push_BN_pad(param_build.get(),"n",n_bignum.get(),BN_num_bytes(n_bignum.get()))
|| (params = OSSL_PARAM_BLD_to_param(param_build.get())) == NULL) {
throw UnsupportedKeyException("Failed to build RSA public key parameters");
}

EVP_PKEY *pkey = NULL;
if (EVP_PKEY_fromdata_init(rsa_ctx.get()) <= 0
|| EVP_PKEY_fromdata(rsa_ctx.get(),&pkey,EVP_PKEY_PUBLIC_KEY,params) <= 0
|| pkey == NULL) {
throw UnsupportedKeyException("Failed to set the RSA public key");
}

if (PEM_write_bio_PUBKEY(pubkey_bio.get(), pkey) == 0) {
throw UnsupportedKeyException("Failed to serialize RSA public key");
}
EVP_PKEY_free(pkey);
OSSL_PARAM_free(params);
#else
std::unique_ptr<RSA, decltype(&RSA_free)> rsa(RSA_new(), RSA_free);
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
rsa->e = e_bignum.get();
rsa->n = n_bignum.get();
rsa->d = nullptr;
#else
RSA_set0_key(rsa.get(), n_bignum.get(), e_bignum.get(), nullptr);
#endif
std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> pkey(EVP_PKEY_new(), EVP_PKEY_free);
if (EVP_PKEY_set1_RSA(pkey.get(), rsa.get()) != 1) {
throw UnsupportedKeyException("Failed to set the public key");
}

std::unique_ptr<BIO, decltype(&BIO_free_all)> pubkey_bio(BIO_new(BIO_s_mem()), BIO_free_all);
if (PEM_write_bio_PUBKEY(pubkey_bio.get(), pkey.get()) == 0) {
throw UnsupportedKeyException("Failed to serialize RSA public key");
}
#endif
e_bignum.release();
n_bignum.release();

char *mem_data;
size_t mem_len = BIO_get_mem_data(pubkey_bio.get(), &mem_data);
Expand Down Expand Up @@ -359,7 +444,7 @@ normalize_absolute_path(const std::string &path) {

void
SciToken::deserialize(const std::string &data, const std::vector<std::string> allowed_issuers) {
m_decoded.reset(new jwt::decoded_jwt(data));
m_decoded.reset(new jwt::decoded_jwt<jwt::traits::kazuho_picojson>(data));

scitokens::Validator val;
val.add_allowed_issuers(allowed_issuers);
Expand Down Expand Up @@ -525,6 +610,43 @@ scitokens::Validator::store_public_ec_key(const std::string &issuer, const std::
if ((size_t)BIO_write(pubkey_bio.get(), public_key.data(), public_key.size()) != public_key.size()) {
return false;
}

std::unique_ptr<BIGNUM, decltype(&BN_free)> x_bignum(BN_new(), BN_free);
std::unique_ptr<BIGNUM, decltype(&BN_free)> y_bignum(BN_new(), BN_free);

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)> pkey(PEM_read_bio_PUBKEY(pubkey_bio.get(),nullptr,nullptr,nullptr), EVP_PKEY_free);
if (!pkey.get()) {return false;}

std::unique_ptr<EC_GROUP, decltype(&EC_GROUP_free)> ec_group(EC_GROUP_new_by_curve_name(EC_NAME),EC_GROUP_free);
if (!ec_group.get()) {
throw UnsupportedKeyException("Unable to get OpenSSL EC group");
}

std::unique_ptr<EC_POINT, decltype(&EC_POINT_free)> q_point(EC_POINT_new(ec_group.get()), EC_POINT_free);
if (!q_point.get()) {
throw UnsupportedKeyException("Unable to get OpenSSL EC point");
}

OSSL_PARAM *params;
if (!EVP_PKEY_todata(pkey.get(), EVP_PKEY_PUBLIC_KEY, &params)) {
throw UnsupportedKeyException("Unable to get OpenSSL public key parameters");
}

void* buf = NULL;
size_t buf_len, max_len = 256;
OSSL_PARAM *p = OSSL_PARAM_locate(params,"pub");
if (!p || !OSSL_PARAM_get_octet_string(p, &buf, max_len, &buf_len)
|| !EC_POINT_oct2point(ec_group.get(), q_point.get(), static_cast<unsigned char*>(buf), buf_len, nullptr)) {
throw UnsupportedKeyException("Failed to to set OpenSSL EC point with public key information");
}

if (!EC_POINT_get_affine_coordinates(ec_group.get(), q_point.get(), x_bignum.get(), y_bignum.get(), NULL)) {
throw UnsupportedKeyException("Unable to get OpenSSL affine coordinates");
}

OSSL_PARAM_free(params);
#else
std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)> pkey
(PEM_read_bio_EC_PUBKEY(pubkey_bio.get(), nullptr, nullptr, nullptr), EC_KEY_free);
if (!pkey) {return false;}
Expand All @@ -539,11 +661,10 @@ scitokens::Validator::store_public_ec_key(const std::string &issuer, const std::
throw UnsupportedKeyException("Unable to get OpenSSL EC point");
}

std::unique_ptr<BIGNUM, decltype(&BN_free)> x_bignum(BN_new(), BN_free);
std::unique_ptr<BIGNUM, decltype(&BN_free)> y_bignum(BN_new(), BN_free);
if (!EC_POINT_get_affine_coordinates_GFp(params, point, x_bignum.get(), y_bignum.get(), nullptr)) {
throw UnsupportedKeyException("Unable to get OpenSSL affine coordinates");
}
#endif

auto x_num = BN_num_bytes(x_bignum.get());
auto y_num = BN_num_bytes(y_bignum.get());
Expand Down Expand Up @@ -577,7 +698,7 @@ scitokens::Validator::store_public_ec_key(const std::string &issuer, const std::
bool
scitokens::Enforcer::scope_validator(const jwt::claim &claim, void *myself) {
auto me = reinterpret_cast<scitokens::Enforcer*>(myself);
if (claim.get_type() != jwt::claim::type::string) {
if (claim.get_type() != jwt::json::type::string) {
return false;
}
std::string scope = claim.as_string();
Expand Down
Loading

0 comments on commit 4916492

Please sign in to comment.