From 8d649c21b61b319623a6c93259b90a6b347a765c Mon Sep 17 00:00:00 2001 From: Ed Tubbs Date: Sat, 23 Sep 2023 00:20:04 -0500 Subject: [PATCH] openenclave: added set_rng and example to enclave cmake: added openenclave config option config: added openenclave config option random: added set_rng for openenclave ci: added openenclave option and U_FORTIFY_SOURCE flag --- .github/workflows/ci.yml | 2 +- CMakeLists.txt | 6 + configure.ac | 19 ++- src/openenclave/enclave/enc.c | 271 +++++++++++++++++++++++++++++++++- src/random.c | 12 ++ 5 files changed, 305 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b24863cb..71995f49b 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,7 +64,7 @@ jobs: run-tests: true packages: python3-dev python3-dbg python dep-opts: "DEBUG=1 SPEED=slow V=1" - config-opts: "--enable-debug CFLAGS=-U_FORTIFY_SOURCE" + config-opts: "--enable-debug --enable-openenclave CFLAGS=-U_FORTIFY_SOURCE" goal: install - name: x86_64-macos host: x86_64-apple-darwin15 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9eaec31cc..3e6bbf33f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ SET(WITH_UNISTRING TRUE CACHE BOOL "enable unistring functions") SET(WITH_WALLET TRUE CACHE BOOL "enable wallet") SET(USE_SSE2 FALSE CACHE BOOL "enable scrypt sse2") SET(USE_TPM2 FALSE CACHE BOOL "enable tpm_tests") +SET(USE_OPENENCLAVE FALSE CACHE BOOL "enable openenclave") SET(RANDOM_DEVICE "/dev/urandom" CACHE STRING "set the device to read random data from") # Set a default build type if none was specified @@ -106,6 +107,9 @@ ENDIF() IF(USE_TPM2) ADD_DEFINITIONS(-DUSE_TPM2=1) ENDIF() +IF(USE_OPENENCLAVE) + ADD_DEFINITIONS(-DUSE_OPENENCLAVE=1) +ENDIF() MESSAGE(STATUS "") MESSAGE(STATUS "Options used to compile and link:") @@ -119,6 +123,8 @@ MESSAGE(STATUS "") MESSAGE(STATUS " USE_SSE2 = ${USE_SSE2}") MESSAGE(STATUS " USE_TPM2 = ${USE_TPM2}") MESSAGE(STATUS "") +MESSAGE(STATUS " openenclave = ${USE_OPENENCLAVE}") +MESSAGE(STATUS "") message(STATUS " library type = ${library_type}") MESSAGE(STATUS "") diff --git a/configure.ac b/configure.ac index bae3f3a2e..af0c0a069 100644 --- a/configure.ac +++ b/configure.ac @@ -52,7 +52,7 @@ build_windows=no CFLAGS="$CFLAGS -W" case $host in *mingw*) - build_windows=yes + build_windows=yes TARGET_OS=windows AC_CHECK_LIB([pthread], [main],, AC_MSG_ERROR(lib missing)) AC_CHECK_LIB([winpthread], [main],, AC_MSG_ERROR(lib missing)) @@ -128,6 +128,12 @@ AC_ARG_ENABLE([unistring], [with_unistring=$enableval], [with_unistring=yes]) +AC_ARG_ENABLE([openenclave], + [AS_HELP_STRING([--enable-openenclave], + [Build with openenclave (default is no)])], + [use_openenclave=$enableval], + [use_openenclave=no]) + AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), [use_tests=$enableval], @@ -195,6 +201,10 @@ if test "x$with_unistring" = xyes; then AC_DEFINE(USE_UNISTRING, 1, [Define this symbol if libunistring works]) fi +if test "x$use_openenclave" = xyes; then + AC_DEFINE(USE_OPENENCLAVE, 1, [Define this symbol if openenclave works]) +fi + AC_CONFIG_HEADERS([config/libdogecoin-config.h]) AC_CONFIG_FILES([Makefile libdogecoin.pc]) AC_SUBST(LIBTOOL_APP_LDFLAGS) @@ -208,6 +218,7 @@ AM_CONDITIONAL([WITH_NET], [test "x$with_net" = "xyes"]) AM_CONDITIONAL([WITH_LOGDB], [test "x$with_logdb" = "xyes"]) AM_CONDITIONAL([WITH_WALLET], [test "x$with_wallet" = "xyes"]) AM_CONDITIONAL([USE_SSE2], [test "x$use_scrypt_sse2" = "xyes"]) +AM_CONDITIONAL([USE_OPENENCLAVE], [test "x$use_openenclave" = "xyes"]) AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT) AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION) AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE) @@ -217,7 +228,7 @@ AC_CONFIG_SUBDIRS([src/secp256k1]) AC_OUTPUT -echo +echo echo "Options used to compile and link:" echo " with tests = $use_tests" echo " with tools = $with_tools" @@ -228,6 +239,8 @@ echo " with unistring = $with_unistring" echo echo " SSE2 Scrypt = $use_scrypt_sse2" echo +echo " openenclave = $use_openenclave" +echo echo " host = $host" echo " target os = $TARGET_OS" echo @@ -236,4 +249,4 @@ echo " CFLAGS = $CFLAGS" echo " CXX = $CXX" echo " CXXFLAGS = $CXXFLAGS" echo " LDFLAGS = $LDFLAGS" -echo +echo diff --git a/src/openenclave/enclave/enc.c b/src/openenclave/enclave/enc.c index efff27994..f9cf67de4 100644 --- a/src/openenclave/enclave/enc.c +++ b/src/openenclave/enclave/enc.c @@ -11,6 +11,9 @@ // Include the libdogecoin headher #include "libdogecoin.h" +// Define the enclave's random number generator +void set_rng(oe_result_t (*ptr)(void *, size_t)); + // This is the function that the host calls. It prints // a message in the enclave before calling back out to // the host to print a message from there too. @@ -34,6 +37,9 @@ void enclave_libdogecoin() oe_result_str(result)); } + // Set the Open Enclave random number generator in libdogecoin + set_rng (&oe_random); + // Let's do something with libdogecoin dogecoin_ecc_start(); @@ -64,16 +70,279 @@ void enclave_libdogecoin() } +//#define PRIVKEYWIFLEN 51 //WIF length for uncompressed keys is 51 and should start with Q. This can be 52 also for compressed keys. 53 internally to lib (+stringterm) +#define PRIVKEYWIFLEN 53 //Function takes 53 but needs to be fixed to take 51. + +//#define MASTERKEYLEN 111 //should be chaincode + privkey; starts with dgpv51eADS3spNJh8 or dgpv51eADS3spNJh9 (112 internally including stringterm? often 128. check this.) +#define MASTERKEYLEN 128 // Function expects 128 but needs to be fixed to take 111. + +//#define PUBKEYLEN 34 //our mainnet addresses are 34 chars if p2pkh and start with D. Internally this is cited as 35 for strings that represent it because +stringterm. +#define PUBKEYLEN 35 // Function expects 35, but needs to be fixed to take 34. + // Lets try running a function for cli // start with some calls the cli apps make // then we'll try and integrate host and cli void enclave_libdogecoin_generate_mnemonic() { MNEMONIC mnemonic = { 0 }; + dogecoin_bool result = false; dogecoin_ecc_start(); - generateEnglishMnemonic("7ced8156e7b0585d13e68f2ccd638137dcdd890ffe8ca699f9da65d4371b1117", "256", mnemonic); + generateRandomEnglishMnemonic("256", mnemonic); printf("mnemonic: %s\n", mnemonic); + // BASIC ADDRESS EXAMPLES + printf("\n\nBEGIN BASIC ADDRESSING:\n\n"); + // create variables + + char wif_privkey[PRIVKEYWIFLEN]; + char p2pkh_pubkey[PUBKEYLEN]; + char wif_master_privkey[MASTERKEYLEN]; + char p2pkh_master_pubkey[PUBKEYLEN]; + char p2pkh_child_pubkey[PUBKEYLEN]; + + // keypair generation + if (generatePrivPubKeypair(wif_privkey, p2pkh_pubkey, 0)) { + printf("Mainnet keypair 1:\n===============================\nPrivate: %s\nPublic: %s\n\n", wif_privkey, p2pkh_pubkey); + } + else { + printf("Error occurred 1.\n"); + oe_result_str(OE_FAILURE); + } + + if (generateHDMasterPubKeypair(wif_master_privkey, p2pkh_master_pubkey, 0)) { + printf("Mainnet master keypair 2:\n===============================\nPrivate: %s\nPublic: %s\n\n", wif_master_privkey, p2pkh_master_pubkey); + } + else { + printf("Error occurred 2.\n"); + oe_result_str(OE_FAILURE); + } + + + if (generateDerivedHDPubkey((const char*)wif_master_privkey, (char*)p2pkh_child_pubkey)) { + printf("Mainnet master derived keypair 3:\n===============================\nPrivate: %s\nPublic: %s\n\n", wif_master_privkey, p2pkh_child_pubkey); + } + else { + printf("Error occurred 3.\n"); + oe_result_str(OE_FAILURE); + } + printf("\n"); + + // keypair verification + if (verifyPrivPubKeypair(wif_privkey, p2pkh_pubkey, 0)) { + printf("Keypair (%s, %s) is valid for mainnet 4.\n\n", wif_privkey, p2pkh_pubkey); + } + else { + printf("Keypair (%s, %s) is not valid for mainnet 4.\n", wif_privkey, p2pkh_pubkey); + oe_result_str(OE_FAILURE); + } + + if (verifyHDMasterPubKeypair(wif_master_privkey, p2pkh_master_pubkey, 0)) { + printf("Keypair (%s, %s) is valid for mainnet 5.\n\n", wif_master_privkey, p2pkh_master_pubkey); + } + else { + printf("Keypair (%s, %s) is not valid for mainnet 5.\n", wif_master_privkey, p2pkh_master_pubkey); + oe_result_str(OE_FAILURE); + } + + if (verifyHDMasterPubKeypair(wif_master_privkey, p2pkh_child_pubkey, 0)) { + printf("Keypair (%s, %s) is valid for mainnet 6.\n\n", wif_master_privkey, p2pkh_child_pubkey); + } + else { + printf("Keypair (%s, %s) is not valid for mainnet 6.\n", wif_master_privkey, p2pkh_child_pubkey); + oe_result_str(OE_FAILURE); + } + printf("\n"); + + // address verification + if (verifyP2pkhAddress(p2pkh_pubkey, strlen(p2pkh_pubkey))) { + printf("Address %s is valid for mainnet 7.\n\n", p2pkh_pubkey); + } + else { + printf("Address %s is not valid for mainnet 7.\n", p2pkh_pubkey); + oe_result_str(OE_FAILURE); + } + + if (verifyP2pkhAddress(p2pkh_master_pubkey, strlen(p2pkh_master_pubkey))) { + printf("Address %s is valid for mainnet 8.\n\n", p2pkh_master_pubkey); + } + else { + printf("Address %s is not valid for mainnet 8.\n", p2pkh_master_pubkey); + oe_result_str(OE_FAILURE); + } + + if (verifyP2pkhAddress(p2pkh_child_pubkey, strlen(p2pkh_child_pubkey))) { + printf("Address %s is valid for mainnet 9.\n", p2pkh_child_pubkey); + } + else { + printf("Address %s is not valid for mainnet 9.\n", p2pkh_child_pubkey); + oe_result_str(OE_FAILURE); + } + printf("\n"); + // END =========================================== + + + // DERIVED HD ADDRESS EXAMPLE + printf("\n\nBEGIN HD ADDRESS DERIVATION EXAMPLE:\n\n"); + size_t extoutsize = 112; + char* extout = dogecoin_char_vla(extoutsize); + char* masterkey_main_ext = "dgpv51eADS3spNJh8h13wso3DdDAw3EJRqWvftZyjTNCFEG7gqV6zsZmucmJR6xZfvgfmzUthVC6LNicBeNNDQdLiqjQJjPeZnxG8uW3Q3gCA3e"; + + if (getDerivedHDAddress(masterkey_main_ext, 0, false, 0, extout, true)) { + printf("Derived HD Addresses:\n%s\n%s\n\n", extout, "dgpv5BeiZXttUioRMzXUhD3s2uE9F23EhAwFu9meZeY9G99YS6hJCsQ9u6PRsAG3qfVwB1T7aQTVGLsmpxMiczV1dRDgzpbUxR7utpTRmN41iV7"); + } else { + printf("getDerviedHDAddress failed!\n"); + oe_result_str(OE_FAILURE); + } + + if (getDerivedHDAddressByPath(masterkey_main_ext, "m/44'/3'/0'/0/0", extout, true)) { + printf("Derived HD Addresses:\n%s\n%s\n", extout, "dgpv5BeiZXttUioRMzXUhD3s2uE9F23EhAwFu9meZeY9G99YS6hJCsQ9u6PRsAG3qfVwB1T7aQTVGLsmpxMiczV1dRDgzpbUxR7utpTRmN41iV7"); + } else { + printf("getDerivedHDAddressByPath failed!\n"); + oe_result_str(OE_FAILURE); + } + dogecoin_free(extout); + // END =========================================== + + + // BASIC TRANSACTION FORMATION EXAMPLE + printf("\n\nBEGIN TRANSACTION FORMATION AND SIGNING:\n\n"); + // declare keys and previous hashes + char *external_p2pkh_addr = "nbGfXLskPh7eM1iG5zz5EfDkkNTo9TRmde"; + char *myprivkey = "ci5prbqz7jXyFPVWKkHhPq4a9N8Dag3TpeRfuqqC2Nfr7gSqx1fy"; + char *mypubkey = "noxKJyGPugPRN4wqvrwsrtYXuQCk7yQEsy"; + char *myscriptpubkey = "76a914d8c43e6f68ca4ea1e9b93da2d1e3a95118fa4a7c88ac"; + char *hash_2_doge = "b4455e7b7b7acb51fb6feba7a2702c42a5100f61f61abafa31851ed6ae076074"; + char *hash_10_doge = "42113bdc65fc2943cf0359ea1a24ced0b6b0b5290db4c63a3329c6601c4616e2"; + + // build transaction + int idx = start_transaction(); + printf("Empty transaction created at index %d.\n", idx); + + if (add_utxo(idx, hash_2_doge, 1)) { + printf("Input of value 2 dogecoin added to the transaction.\n"); + } + else { + printf("Error occurred.\n"); + oe_result_str(OE_FAILURE); + } + + if (add_utxo(idx, hash_10_doge, 1)) { + printf("Input of value 10 dogecoin added to the transaction.\n"); + } + else { + printf("Error occurred.\n"); + oe_result_str(OE_FAILURE); + } + + if (add_output(idx, external_p2pkh_addr, "5.0")) { + printf("Output of value 5 dogecoin added to the transaction.\n"); + } + else { + printf("Error occurred.\n"); + oe_result_str(OE_FAILURE); + } + + // save the finalized unsigned transaction to a new index in the hash table + // save the finalized unsigned transaction to a new index in the hash table + int idx2 = store_raw_transaction(finalize_transaction(idx, external_p2pkh_addr, "0.00226", "12", mypubkey)); + if (idx2 > 0) { + printf("Change returned to address %s and finalized unsigned transaction saved at index %d.\n", mypubkey, idx2); + } + else { + printf("Error occurred.\n"); + oe_result_str(OE_FAILURE); + } + + // sign transaction + if (sign_transaction(idx, myscriptpubkey, myprivkey)) { + printf("\nAll transaction inputs signed successfully. \nFinal transaction hex: %s\n.", get_raw_transaction(idx)); + } + else { + printf("Error occurred.\n"); + oe_result_str(OE_FAILURE); + } + remove_all(); + // END =========================================== + + + // BASIC MESSAGE SIGNING EXAMPLE + printf("\n\nBEGIN BASIC MESSAGE SIGNING:\n\n"); + char* msg = "This is just a test message"; + char* privkey = "QUtnMFjt3JFk1NfeMe6Dj5u4p25DHZA54FsvEFAiQxcNP4bZkPu2"; + char* address = "D6a52RGbfvKDzKTh8carkGd1vNdAurHmaS"; + char* sig = sign_message(privkey, msg); + if (verify_message(sig, msg, address)) { + printf("Addresses match!\n"); + } else { + printf("Addresses do not match!\n"); + oe_result_str(OE_FAILURE); + } + + // testcase 2: + // assert modified msg will cause verification failure: + msg = "This is a new test message"; + if (!verify_message(sig, msg, address)) { + printf("Addresses do not match!\n"); + } else { + printf("Addresses match!\n"); + oe_result_str(OE_FAILURE); + } + + // testcase 3: + msg = "This is just a test message"; + if (verify_message(sig, msg, address)) { + printf("Addresses match!\n"); + } else { + printf("Addresses do not match!\n"); + oe_result_str(OE_FAILURE); + } + dogecoin_free(sig); + // END =========================================== + + + // ADVANCED MESSAGE SIGNING EXAMPLE + printf("\n\nBEGIN ADVANCED MESSAGE SIGNING:\n\n"); + for (int i = 0; i < 10; i++) { + // key 1: + int key_id = start_key(false); + eckey* key = find_eckey(key_id); + char* msg = "This is a test message"; + char* sig = sign_message(key->private_key_wif, msg); + if (verify_message(sig, msg, key->address)) { + printf("Addresses match!\n"); + } else { + printf("Message verification failed!\n"); + oe_result_str(OE_FAILURE); + } + remove_eckey(key); + dogecoin_free(sig); + + // key 2: + int key_id2 = start_key(true); + eckey* key2 = find_eckey(key_id2); + char* msg2 = "This is a test message"; + char* sig2 = sign_message(key2->private_key_wif, msg2); + if (verify_message(sig2, msg2, key2->address)) { + printf("Addresses match!\n"); + } else { + printf("Message verification failed!\n"); + oe_result_str(OE_FAILURE); + } + + // test message signature verification failure: + msg2 = "This is an altered test message"; + if (!verify_message(sig2, msg2, key2->address)) { + printf("Addresses do not match!\n"); + } else { + printf("Message verification failed!\n"); + oe_result_str(OE_FAILURE); + } + remove_eckey(key2); + dogecoin_free(sig2); + } + + printf("\nTESTS COMPLETE!\n"); dogecoin_ecc_stop(); + } diff --git a/src/random.c b/src/random.c index 2b950f1af..4e52d6299 100644 --- a/src/random.c +++ b/src/random.c @@ -147,6 +147,12 @@ dogecoin_bool dogecoin_random_bytes_internal(uint8_t* buf, uint32_t len, const u return true; } #else +/* Define a function pointer for random */ +int (*rng_ptr) (void*, size_t) = NULL; +void set_rng(int (*ptr)(void *, size_t)) + { + rng_ptr = ptr; + } void dogecoin_random_init_internal(void) { } @@ -196,6 +202,12 @@ dogecoin_bool dogecoin_random_bytes_internal(uint8_t* buf, uint32_t len, const u errno = ENOSYS; return -1; #else +#ifdef USE_OPENENCLAVE + if (rng_ptr != NULL) + if (rng_ptr(buf, len) == 0) + return true; +#endif + (void)update_seed; //unused FILE* frand = fopen("/dev/urandom", "r"); // figure out why RANDOM_DEVICE is undeclared here if (!frand)