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

Added unit tests for native RSA verifier #49

Merged
merged 5 commits into from
Jan 29, 2020
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*.wast.hpp
/build/
/build-debug/
/unittests/test-contracts/build/

/doxygen
/*.doxygen
Expand Down
2 changes: 1 addition & 1 deletion scripts/daobet_build_ubuntu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ if [ -z $SKIP_DEPS_CHECK ]; then
printf "\\n"

printf "Checking Boost library (${BOOST_VERSION}) installation...\\n"
BOOSTVERSION=$( grep "#define BOOST_VERSION" "$INSTALL_PREFIX/opt/boost/include/boost/version.hpp" 2>/dev/null | tail -1 | tr -s ' ' | cut -d\ -f3 )
BOOSTVERSION=$( grep "#define BOOST_VERSION" "$BOOST_ROOT/include/boost/version.hpp" 2>/dev/null | tail -1 | tr -s ' ' | cut -d\ -f3 )
if [ "${BOOSTVERSION}" != "${BOOST_VERSION_MAJOR}0${BOOST_VERSION_MINOR}0${BOOST_VERSION_PATCH}" ]; then
printf "Installing Boost library...\\n"
curl -LO https://dl.bintray.com/boostorg/release/${BOOST_VERSION_MAJOR}.${BOOST_VERSION_MINOR}.${BOOST_VERSION_PATCH}/source/boost_$BOOST_VERSION.tar.bz2 \
Expand Down
1 change: 1 addition & 0 deletions unittests/contracts.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ namespace eosio {
MAKE_READ_WASM_ABI(test_api_db, test_api_db, test-contracts)
MAKE_READ_WASM_ABI(test_api_multi_index, test_api_multi_index, test-contracts)
MAKE_READ_WASM_ABI(test_ram_limit, test_ram_limit, test-contracts)
MAKE_READ_WASM_ABI(rsa, rsa, test-contracts)
};
} /// eosio::testing
} /// eosio
187 changes: 187 additions & 0 deletions unittests/rsa_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
#include <boost/test/unit_test.hpp>
#pragma GCC diagnostic pop

#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>

#include <Runtime/Runtime.h>

#include <fc/variant_object.hpp>
#include <fc/io/json.hpp>
#include <fc/crypto/sha256.hpp>

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/x509.h>

#include <boost/algorithm/string/predicate.hpp>

#include <contracts.hpp>

#ifdef NON_VALIDATING_TEST
#define TESTER tester
#else
#define TESTER validating_tester
#endif

using namespace eosio;
using namespace eosio::chain;
using namespace eosio::testing;
using namespace fc;

using mvo = fc::mutable_variant_object;
using bytes = std::vector<char>;

using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
using BIO_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>;
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;

class rsa_tester : public TESTER {
public:
void deploy_contract() {
create_accounts( {N(rsa)} );
set_code( N(rsa), contracts::rsa_wasm() );
set_abi( N(rsa), contracts::rsa_abi().data() );
}

RSA_ptr new_keys() {
static bool init = true;
if( init ) {
ERR_load_crypto_strings();
init = false;
}

auto rsa = RSA_ptr(RSA_generate_key(2048, 65537, NULL, NULL), ::RSA_free);
return rsa;
}

std::string sign(const RSA_ptr& rsa, const sha256& digest) {
bytes signature;
signature.resize(RSA_size(rsa.get()));
uint32_t len;
RSA_sign(NID_sha256, (uint8_t*)digest.data(), 32,
(unsigned char*)signature.data(), &len, rsa.get());
return fc::base64_encode(signature.data(), signature.size());
}

std::string pem_pubkey(const RSA_ptr& rsa) {
auto pkey = EVP_PKEY_ptr(EVP_PKEY_new(), ::EVP_PKEY_free);
EVP_PKEY_set1_RSA(pkey.get(), rsa.get());

auto mem = BIO_ptr(BIO_new(BIO_s_mem()), ::BIO_free);
PEM_write_bio_PUBKEY(mem.get(), pkey.get());

BUF_MEM *bio_buf;
BIO_get_mem_ptr(mem.get(), &bio_buf);

std::stringstream ss({bio_buf->data, bio_buf->length});
std::string pem;

while (ss) {
std::string tmp;
std::getline(ss, tmp);
if (tmp[0] != '-') {
pem += tmp;
}
}

return pem;
}
};

BOOST_AUTO_TEST_SUITE(rsa_tests)

BOOST_FIXTURE_TEST_CASE( success, rsa_tester ) {
deploy_contract();

std::string message = "I'm message";
fc::sha256 digest = fc::sha256::hash(message);
auto keys = new_keys();
auto signature = sign(keys, digest);

push_action(N(rsa), N(verify), N(rsa), mvo()
("digest", digest)
("sig", signature)
("pubkey", pem_pubkey(keys))
);
}

BOOST_FIXTURE_TEST_CASE( invalid_signature, rsa_tester ) {
deploy_contract();

std::string message = "I'm new message";
fc::sha256 digest = fc::sha256::hash(message);
auto keys = new_keys();
auto keys2 = new_keys();
auto signature = sign(keys2, digest); // <- signature by another key

BOOST_CHECK_THROW(push_action(N(rsa), N(verify), N(rsa), mvo()
("digest", digest)
("sig", signature)
("pubkey", pem_pubkey(keys))
), fc::exception);
}

BOOST_FIXTURE_TEST_CASE( invalid_key, rsa_tester ) {
deploy_contract();

std::string message = "I'm new message";
fc::sha256 digest = fc::sha256::hash(message);
auto keys = new_keys();
auto keys2 = new_keys();
auto signature = sign(keys, digest);
auto pem = pem_pubkey(keys2); // <- another key

BOOST_CHECK_THROW(push_action(N(rsa), N(verify), N(rsa), mvo()
("digest", digest)
("sig", signature)
("pubkey", pem)
), fc::exception);
}

BOOST_FIXTURE_TEST_CASE( invalid_digest, rsa_tester ) {
deploy_contract();

std::string message = "I'm new message";
std::string message2 = "I'm another new message";

fc::sha256 digest = fc::sha256::hash(message);
fc::sha256 digest2 = fc::sha256::hash(message2); // <- digest from another message

auto keys = new_keys();
auto signature = sign(keys, digest);

BOOST_CHECK_THROW(push_action(N(rsa), N(verify), N(rsa), mvo()
("digest", digest2)
("sig", signature)
("pubkey", pem_pubkey(keys))
), fc::exception);
}

BOOST_FIXTURE_TEST_CASE( long_message, rsa_tester ) {
deploy_contract();

std::string message;
for (auto i = 0; i < 1024; ++i) { // <- generate long message
message += "A";
}

auto digest = fc::sha256::hash(message);
auto keys = new_keys();
auto signature = sign(keys, digest);

push_action(N(rsa), N(verify), N(rsa), mvo()
("digest", digest)
("sig", signature)
("pubkey", pem_pubkey(keys))
);
}

BOOST_AUTO_TEST_SUITE_END()
8 changes: 8 additions & 0 deletions unittests/test-contracts/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# macro add *.abi files to executable resources
macro(add_contract_with_abi CONTRACT_NAME TARGET)
add_contract( ${TARGET} ${CONTRACT_NAME} ${ARGN} )
get_target_property(BINOUTPUT ${TARGET} BINARY_DIR)
set_target_properties( ${TARGET} PROPERTIES RESOURCE ${BINOUTPUT}/${TARGET}.abi)
endmacro()

if( EOSIO_COMPILE_TEST_CONTRACTS )
set(EOSIO_WASM_OLD_BEHAVIOR "Off")
find_package( eosio.cdt REQUIRED )
Expand All @@ -18,3 +25,4 @@ add_subdirectory( test_api )
add_subdirectory( test_api_db )
add_subdirectory( test_api_multi_index )
add_subdirectory( test_ram_limit )
add_subdirectory( rsa )
12 changes: 9 additions & 3 deletions unittests/test-contracts/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
test_ram_limit contract was compiled with eosio.cdt v1.4.1
# BUILD
- Install EOSIO.CDT v1.6.1
- ```EOSIO_CDT_CMAKE=<PATH_TO_EOSIO_CDT_CMAKE_MODULE_DIR> ./build.sh```

That contract was ported to compile with eosio.cdt v1.5.0, but the test that uses it is very sensitive to stdlib/eosiolib changes, compilation flags and linker flags.
`EOSIO_CDT_CMAKE` is path to `eosio.cdt` cmake module on your host, usually located at `/usr/lib/cmake/eosio.cdt` after install EOSIO.CDT from package manager.
If you don't specify `EOSIO_CDT_CMAKE` then script will use `/usr/lib/cmake/eosio.cdt` path. If your cmake module located at another dir than `/usr/lib/cmake/eosio.cdt` you have to explicitly set path to script.

The remaining contracts have been ported to compile with eosio.cdt v1.6.x. They were compiled with a patched version of eosio.cdt v1.6.0-rc1 (commit 1c9180ff5a1e431385180ce459e11e6a1255c1a4).

# NOTE
`test_ram_limit` contract was compiled with eosio.cdt v1.4.1 and build.sh doesn't rebuild it.
That contract can be compiled with eosio.cdt v1.5.0, but the test that uses it is very sensitive to stdlib/eosiolib changes, compilation flags and linker flags.
4 changes: 3 additions & 1 deletion unittests/test-contracts/asserter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
if( EOSIO_COMPILE_TEST_CONTRACTS )
add_contract( asserter asserter asserter.cpp )
add_contract_with_abi( asserter asserter asserter.cpp )
target_include_directories( asserter PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
install( TARGETS asserter DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/asserter.wasm ${CMAKE_CURRENT_BINARY_DIR}/asserter.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/asserter.abi ${CMAKE_CURRENT_BINARY_DIR}/asserter.abi COPYONLY )
Expand Down
2 changes: 1 addition & 1 deletion unittests/test-contracts/asserter/asserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE
*/
#include "asserter.hpp"
#include <asserter.hpp>

using namespace eosio;

Expand Down
Binary file modified unittests/test-contracts/asserter/asserter.wasm
Binary file not shown.
19 changes: 19 additions & 0 deletions unittests/test-contracts/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#! /bin/bash
set -e

EOSIO_CDT_CMAKE=${EOSIO_CDT_CMAKE:-/usr/lib/cmake/eosio.cdt}

if [[ ! -d ${EOSIO_CDT_CMAKE} ]]; then
echo "Invalid EOSIO_CDT_CMAKE: dir doesn't exists"
exit 1
fi

EOSIO_CDT_TOOLCHAIN="${EOSIO_CDT_CMAKE}/EosioWasmToolchain.cmake"

if [[ ! -d "./build" ]]; then
mkdir build
fi

cd build
cmake -DEOSIO_COMPILE_TEST_CONTRACTS=1 -DCMAKE_TOOLCHAIN_FILE=${EOSIO_CDT_TOOLCHAIN} ..
make install
4 changes: 3 additions & 1 deletion unittests/test-contracts/deferred_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
if( EOSIO_COMPILE_TEST_CONTRACTS )
add_contract( deferred_test deferred_test deferred_test.cpp )
add_contract_with_abi( deferred_test deferred_test deferred_test.cpp )
target_include_directories( deferred_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
install( TARGETS deferred_test DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/deferred_test.wasm ${CMAKE_CURRENT_BINARY_DIR}/deferred_test.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/deferred_test.abi ${CMAKE_CURRENT_BINARY_DIR}/deferred_test.abi COPYONLY )
Expand Down
2 changes: 1 addition & 1 deletion unittests/test-contracts/deferred_test/deferred_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE
*/
#include "deferred_test.hpp"
#include <deferred_test.hpp>
#include <eosio/transaction.hpp>

using namespace eosio;
Expand Down
Binary file modified unittests/test-contracts/deferred_test/deferred_test.wasm
Binary file not shown.
4 changes: 3 additions & 1 deletion unittests/test-contracts/integration_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
if( EOSIO_COMPILE_TEST_CONTRACTS )
add_contract( integration_test integration_test integration_test.cpp )
add_contract_with_abi( integration_test integration_test integration_test.cpp )
target_include_directories( integration_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
install( TARGETS integration_test DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/integration_test.wasm ${CMAKE_CURRENT_BINARY_DIR}/integration_test.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/integration_test.abi ${CMAKE_CURRENT_BINARY_DIR}/integration_test.abi COPYONLY )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE
*/
#include "integration_test.hpp"
#include <integration_test.hpp>

using namespace eosio;

Expand Down
Binary file modified unittests/test-contracts/integration_test/integration_test.wasm
Binary file not shown.
4 changes: 3 additions & 1 deletion unittests/test-contracts/noop/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
if( EOSIO_COMPILE_TEST_CONTRACTS )
add_contract( noop noop noop.cpp )
add_contract_with_abi( noop noop noop.cpp )
target_include_directories( noop PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
install( TARGETS noop DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/noop.wasm ${CMAKE_CURRENT_BINARY_DIR}/noop.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/noop.abi ${CMAKE_CURRENT_BINARY_DIR}/noop.abi COPYONLY )
Expand Down
2 changes: 1 addition & 1 deletion unittests/test-contracts/noop/noop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE
*/
#include "noop.hpp"
#include <noop.hpp>

using namespace eosio;

Expand Down
Binary file modified unittests/test-contracts/noop/noop.wasm
Binary file not shown.
4 changes: 3 additions & 1 deletion unittests/test-contracts/payloadless/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
if( EOSIO_COMPILE_TEST_CONTRACTS )
add_contract( payloadless payloadless payloadless.cpp )
add_contract_with_abi( payloadless payloadless payloadless.cpp )
target_include_directories( payloadless PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
install( TARGETS payloadless DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/payloadless.wasm ${CMAKE_CURRENT_BINARY_DIR}/payloadless.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/payloadless.abi ${CMAKE_CURRENT_BINARY_DIR}/payloadless.abi COPYONLY )
Expand Down
2 changes: 1 addition & 1 deletion unittests/test-contracts/payloadless/payloadless.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @copyright defined in eos/LICENSE
*/

#include "payloadless.hpp"
#include <payloadless.hpp>

using namespace eosio;

Expand Down
Binary file modified unittests/test-contracts/payloadless/payloadless.wasm
Binary file not shown.
4 changes: 3 additions & 1 deletion unittests/test-contracts/proxy/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
if( EOSIO_COMPILE_TEST_CONTRACTS )
add_contract( proxy proxy proxy.cpp )
add_contract_with_abi( proxy proxy proxy.cpp )
target_include_directories( proxy PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
install( TARGETS proxy DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/proxy.wasm ${CMAKE_CURRENT_BINARY_DIR}/proxy.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/proxy.abi ${CMAKE_CURRENT_BINARY_DIR}/proxy.abi COPYONLY )
Expand Down
2 changes: 1 addition & 1 deletion unittests/test-contracts/proxy/proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file
* @copyright defined in eos/LICENSE
*/
#include "proxy.hpp"
#include <proxy.hpp>
#include <eosio/transaction.hpp>

using namespace eosio;
Expand Down
Binary file modified unittests/test-contracts/proxy/proxy.wasm
Binary file not shown.
8 changes: 8 additions & 0 deletions unittests/test-contracts/rsa/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
if( EOSIO_COMPILE_TEST_CONTRACTS )
add_contract_with_abi( rsa rsa rsa.cpp )
target_include_directories( rsa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} )
install( TARGETS rsa DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )
else()
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/rsa.wasm ${CMAKE_CURRENT_BINARY_DIR}/rsa.wasm COPYONLY )
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/rsa.abi ${CMAKE_CURRENT_BINARY_DIR}/rsa.abi COPYONLY )
endif()
Loading