diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1e3c7eed..f881fa24 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 + uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -81,6 +81,6 @@ jobs: ./build/main - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 + uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 84608e20..d9afeba4 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # v3.27.1 + uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5 with: sarif_file: results.sarif diff --git a/.gitignore b/.gitignore index 3beefbb4..9e273b75 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ __pycache__/ .pio/ test/*/test_* +/.clang-format diff --git a/CMakeLists.txt b/CMakeLists.txt index d31e3654..e3cdfd43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,20 +9,20 @@ cmake_policy(SET CMP0135 NEW) include(GNUInstallDirs) project( - atsdk - VERSION 0.0.1 - DESCRIPTION "Atsign's atSDK library" - HOMEPAGE_URL https://atsign.com - LANGUAGES C + atsdk + VERSION 0.0.1 + DESCRIPTION "Atsign's atSDK library" + HOMEPAGE_URL https://atsign.com + LANGUAGES C ) # Determine if atchops is being built as a subproject using add_subdirectory() -if(NOT DEFINED ATSDK_AS_SUBPROJECT) - set(ATSDK_AS_SUBPROJECT ON) - if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - set(ATSDK_AS_SUBPROJECT OFF) - endif() -endif() +if (NOT DEFINED ATSDK_AS_SUBPROJECT) + set(ATSDK_AS_SUBPROJECT ON) + if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(ATSDK_AS_SUBPROJECT OFF) + endif () +endif () message(STATUS "[ATSDK] ATSDK_AS_SUBPROJECT: ${ATSDK_AS_SUBPROJECT}") # install each package @@ -37,45 +37,55 @@ message(STATUS "Building atclient") set(ATCLIENT_BUILD_TESTS ${ATSDK_BUILD_TESTS}) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/packages/atclient) -if(NOT ESP_PLATFORM) - # install dependencies - set( - ATSDK_TARGETS - mbedtls - mbedx509 - mbedcrypto - everest - p256m - uuid4-static - atchops - cjson - atlogger - atclient - ) +message(STATUS "Building atcommons") +set(ATCOMMONS_BUILD_TESTS ${ATSDK_BUILD_TESTS}) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/packages/atcommons) - install( - TARGETS ${ATSDK_TARGETS} - EXPORT ${PROJECT_NAME}-config - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) +message(STATUS "Building atauth") +set(ATAUTH_BUILD_TESTS ${ATSDK_BUILD_TESTS}) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/packages/atauth) - # export dependencies - if(NOT ATSDK_AS_SUBPROJECT) - export(PACKAGE ${PROJECT_NAME}) +if (NOT ESP_PLATFORM) + # install dependencies + set( + ATSDK_TARGETS + mbedtls + mbedx509 + mbedcrypto + everest + p256m + uuid4-static + atchops + cjson + atlogger + atclient + atcommons + atauth + ) - # install as a config.cmake install( - EXPORT ${PROJECT_NAME}-config - NAMESPACE ${PROJECT_NAME}:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} - FILE ${PROJECT_NAME}-config.cmake + TARGETS ${ATSDK_TARGETS} + EXPORT ${PROJECT_NAME}-config + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) - # export the config.cmake - export( - EXPORT ${PROJECT_NAME}-config - NAMESPACE ${PROJECT_NAME}:: - FILE "cmake/${PROJECT_NAME}-config.cmake" - ) - endif() -endif() + # export dependencies + if (NOT ATSDK_AS_SUBPROJECT) + export(PACKAGE ${PROJECT_NAME}) + + # install as a config.cmake + install( + EXPORT ${PROJECT_NAME}-config + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + FILE ${PROJECT_NAME}-config.cmake + ) + + # export the config.cmake + export( + EXPORT ${PROJECT_NAME}-config + NAMESPACE ${PROJECT_NAME}:: + FILE "cmake/${PROJECT_NAME}-config.cmake" + ) + endif () +endif () diff --git a/cmake/atauth.cmake b/cmake/atauth.cmake new file mode 100644 index 00000000..e6040f12 --- /dev/null +++ b/cmake/atauth.cmake @@ -0,0 +1,10 @@ +if(NOT TARGET atauth) + include(FetchContent) + message( + STATUS + "[ATAUTH] package not found, fetching from local repository.." + ) + FetchContent_Declare(atauth SOURCE_DIR ${atauth_DIR}) + FetchContent_MakeAvailable(atauth) + install(TARGETS atauth) +endif() \ No newline at end of file diff --git a/cmake/atclient.cmake b/cmake/atclient.cmake index 1c80bcba..1ce394c8 100644 --- a/cmake/atclient.cmake +++ b/cmake/atclient.cmake @@ -1,9 +1,10 @@ if(NOT TARGET atclient) - message( - STATUS - "[ATCLIENT] package not found, fetching from local repository.." - ) - fetchcontent_declare(atclient SOURCE_DIR ${atclient_DIR}) - fetchcontent_makeavailable(atclient) - install(TARGETS atclient) + include(FetchContent) + message( + STATUS + "[ATCLIENT] package not found, fetching from local repository.." + ) + FetchContent_Declare(atclient SOURCE_DIR ${atclient_DIR}) + FetchContent_MakeAvailable(atclient) + install(TARGETS atclient) endif() diff --git a/cmake/atcommons.cmake b/cmake/atcommons.cmake new file mode 100644 index 00000000..2823dc96 --- /dev/null +++ b/cmake/atcommons.cmake @@ -0,0 +1,10 @@ +if(NOT TARGET atcommons) + include(FetchContent) + message( + STATUS + "[ATCOMMONS] package not found, fetching from local repository.. [PATH: ${atcommons_DIR}]" + ) + FetchContent_Declare(atcommons SOURCE_DIR ${atcommons_DIR}) + FetchContent_MakeAvailable(atcommons) + install(TARGETS atcommons) +endif() diff --git a/cmake/atlogger.cmake b/cmake/atlogger.cmake index 2451929c..0588390f 100644 --- a/cmake/atlogger.cmake +++ b/cmake/atlogger.cmake @@ -1,9 +1,10 @@ if(NOT TARGET atlogger) - message( - STATUS - "[ATLOGGER] package not found, fetching from local repository.." - ) - fetchcontent_declare(atlogger SOURCE_DIR ${atlogger_DIR}) - fetchcontent_makeavailable(atlogger) - install(TARGETS atlogger) + include(FetchContent) + message( + STATUS + "[ATLOGGER] package not found, fetching from local repository.." + ) + fetchcontent_declare(atlogger SOURCE_DIR ${atlogger_DIR}) + fetchcontent_makeavailable(atlogger) + install(TARGETS atlogger) endif() diff --git a/cmake/find_cjson.cmake b/cmake/find_cjson.cmake index ad7cc856..550ae09d 100644 --- a/cmake/find_cjson.cmake +++ b/cmake/find_cjson.cmake @@ -4,10 +4,10 @@ set(CJSON_BUILD_SHARED_LIBS OFF CACHE BOOL "Build cjson shared libraries") option(ENABLE_CJSON_TEST "Enable tests for cjson" OFF) set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE OPT_IN) # only try find_package if FIND_PACKAGE_ARGS is set -message(STATUS "[cjson] fetching package...") +message(STATUS "[cJSON] fetching package...") include(FetchContent) -fetchcontent_declare( +FetchContent_Declare( cjson URL https://github.com/DaveGamble/cJSON/archive/refs/tags/v1.7.17.zip URL_HASH @@ -15,5 +15,5 @@ fetchcontent_declare( # FIND_PACKAGE_ARGS 1.7.17 QUIET CONFIG ) -fetchcontent_makeavailable(cjson) +FetchContent_MakeAvailable(cjson) install(TARGETS cjson) diff --git a/examples/desktop/at_talk/src/main.c b/examples/desktop/at_talk/src/main.c index 56c47dd3..4693b5d6 100644 --- a/examples/desktop/at_talk/src/main.c +++ b/examples/desktop/at_talk/src/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #define ROOT_HOST "root.atsign.org" #define ROOT_PORT 64 @@ -96,8 +97,8 @@ int main(int argc, char *argv[]) { * 4. Authenticate client connection (for crud operations) */ pthread_mutex_lock(&client_mutex); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); if ((ret = atclient_pkam_authenticate(&atclient1, from_atsign, &atkeys, &options)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "\natclient_pkam_authenticate: %d\n", ret); goto exit; @@ -189,7 +190,7 @@ exit: { pthread_mutex_destroy(&monitor_mutex); ret = pthread_cancel(tid); atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "pthread exit: %d\n", ret); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); return ret; } } @@ -340,8 +341,8 @@ static int reconnect_clients(atclient *monitor, atclient *ctx, const char *atser * 1. Reconnect client connection */ atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Reconnecting client connection...\n"); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); if ((ret = atclient_pkam_authenticate(ctx, from_atsign, atkeys, &options)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_pkam_authenticate: %d\n", ret); return ret; diff --git a/examples/desktop/cram_authenticate/.gitignore b/examples/desktop/cram_authenticate/.gitignore new file mode 100644 index 00000000..473f75c8 --- /dev/null +++ b/examples/desktop/cram_authenticate/.gitignore @@ -0,0 +1 @@ +/*build*/ diff --git a/examples/desktop/cram_authenticate/CMakeLists.txt b/examples/desktop/cram_authenticate/CMakeLists.txt new file mode 100644 index 00000000..40eb536c --- /dev/null +++ b/examples/desktop/cram_authenticate/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.19) + +project(cram_authenticate LANGUAGES C VERSION 0.0.1) + +add_executable(main ${CMAKE_CURRENT_LIST_DIR}/src/main.c) + +find_package(atsdk CONFIG REQUIRED) + +target_link_libraries(main PRIVATE atsdk::atclient atsdk::atchops atsdk::atcommons) + diff --git a/examples/desktop/cram_authenticate/develop.sh b/examples/desktop/cram_authenticate/develop.sh new file mode 100755 index 00000000..2d4164b9 --- /dev/null +++ b/examples/desktop/cram_authenticate/develop.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -eu +FULL_PATH_TO_SCRIPT="$(realpath "${BASH_SOURCE[0]}")" +SCRIPT_DIRECTORY="$(dirname "$FULL_PATH_TO_SCRIPT")" +cd "$SCRIPT_DIRECTORY/../../../packages/atclient" +cmake -S . -B build +sudo cmake --build build --target install +pwd +cd "$SCRIPT_DIRECTORY" +cmake -S . -B build +cmake --build build --target all +echo "Running main:" +echo "" +echo "" +cd build && ./main +cd .. diff --git a/examples/desktop/cram_authenticate/src/main.c b/examples/desktop/cram_authenticate/src/main.c new file mode 100644 index 00000000..72d39376 --- /dev/null +++ b/examples/desktop/cram_authenticate/src/main.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +#define ROOT_HOST "root.atsign.org" +#define ROOT_PORT 64 + +#define CRAM_SECRET "66e026167a79cb7e9d190afe7b01b3fc4f31bc3866a08cdcec06d82a7296e9febcac5d4f4a081728fb0ec9d08f27d4f866bd6570f3fe20c65464ace76643becb" +#define ATSIGN "@disciplinarygemini" + +#define TAG "cram_authenticate" + +int main(int argc, char **argv) { + int ret = 1; + + atlogger_set_logging_level(ATLOGGER_LOGGING_LEVEL_DEBUG); + + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); + + atclient atclient; + atclient_init(&atclient); + + const char *atsign = ATSIGN; + const char *cram_secret = &CRAM_SECRET[0]; + + if ((ret = atclient_cram_authenticate(&atclient, ATSIGN, cram_secret, &options)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to authenticate\n"); + goto exit; + } else { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Authenticated\n"); + } + +exit: { + atclient_free(&atclient); + atclient_authenticate_options_free(&options); + return ret; +} +} \ No newline at end of file diff --git a/examples/desktop/crud/delete.c b/examples/desktop/crud/delete.c index f996a100..dbe8b09a 100644 --- a/examples/desktop/crud/delete.c +++ b/examples/desktop/crud/delete.c @@ -36,8 +36,8 @@ int main() { atclient_atkey_init(&atkey); atclient_atkeys_init(&atkeys); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); if ((ret = atclient_atkeys_populate_from_path(&atkeys, ATKEYS_FILE_PATH)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to populate atkeys"); @@ -65,7 +65,7 @@ exit: { atclient_free(&atclient); atclient_atkey_free(&atkey); atclient_atkeys_free(&atkeys); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); return ret; } } diff --git a/examples/desktop/crud/get_publickey.c b/examples/desktop/crud/get_publickey.c index e89be502..9d748413 100644 --- a/examples/desktop/crud/get_publickey.c +++ b/examples/desktop/crud/get_publickey.c @@ -45,8 +45,8 @@ int main() { atclient_atkeys_init(&atkeys); atclient_atkeys_populate_from_path(&atkeys, ATKEYS_FILE_PATH); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); char *atkeystr = NULL; @@ -94,7 +94,7 @@ exit: { atclient_atkeys_free(&atkeys); atclient_atkey_free(&atkey); atclient_free(&atclient); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); free(atkeystr); return ret; } diff --git a/examples/desktop/crud/get_selfkey.c b/examples/desktop/crud/get_selfkey.c index 55858f72..c1c8c35f 100644 --- a/examples/desktop/crud/get_selfkey.c +++ b/examples/desktop/crud/get_selfkey.c @@ -48,8 +48,8 @@ int main() { atclient_atkeys_init(&atkeys); atclient_atkeys_populate_from_path(&atkeys, ATKEYS_FILE_PATH); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); char *atkeystr = NULL; @@ -90,7 +90,7 @@ exit: { atclient_atkey_free(&atkey); atclient_atkeys_free(&atkeys); atclient_free(&atclient); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); free(atkeystr); return ret; } diff --git a/examples/desktop/crud/get_sharedkey.c b/examples/desktop/crud/get_sharedkey.c index ee1a3a54..73d3aae7 100644 --- a/examples/desktop/crud/get_sharedkey.c +++ b/examples/desktop/crud/get_sharedkey.c @@ -61,8 +61,8 @@ int main() { atclient_atkeys_init(&atkeys); atclient_atkeys_populate_from_path(&atkeys, ATSIGN_ATKEYS_FILE_PATH); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); char *atkeystr = NULL; @@ -128,7 +128,7 @@ exit: { atclient_atkey_free(&atkey); atclient_atkeys_free(&atkeys); atclient_free(&atclient); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); free(atkeystr); return ret; } diff --git a/examples/desktop/crud/put_publickey.c b/examples/desktop/crud/put_publickey.c index 0b013711..7ba455bc 100644 --- a/examples/desktop/crud/put_publickey.c +++ b/examples/desktop/crud/put_publickey.c @@ -47,8 +47,8 @@ int main() { atclient_atkeys_init(&atkeys); atclient_atkeys_populate_from_path(&atkeys, ATKEYS_FILE_PATH); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); char *atkeystr = NULL; @@ -93,7 +93,7 @@ exit: { atclient_atkeys_free(&atkeys); atclient_atkey_free(&atkey); atclient_free(&atclient); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); free(atkeystr); return ret; } diff --git a/examples/desktop/crud/put_selfkey.c b/examples/desktop/crud/put_selfkey.c index b006aacd..498053f5 100644 --- a/examples/desktop/crud/put_selfkey.c +++ b/examples/desktop/crud/put_selfkey.c @@ -47,8 +47,8 @@ int main() { atclient_atkeys_init(&atkeys); atclient_atkeys_populate_from_path(&atkeys, ATKEYS_FILE_PATH); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); char *atkeystr = NULL; @@ -91,7 +91,7 @@ exit: { atclient_atkeys_free(&atkeys); atclient_atkey_free(&atkey); atclient_free(&atclient); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); free(atkeystr); return ret; } diff --git a/examples/desktop/crud/put_sharedkey.c b/examples/desktop/crud/put_sharedkey.c index 69859769..720617b3 100644 --- a/examples/desktop/crud/put_sharedkey.c +++ b/examples/desktop/crud/put_sharedkey.c @@ -48,8 +48,8 @@ int main() { atclient_atkeys_init(&atkeys); atclient_atkeys_populate_from_path(&atkeys, ATKEYS_FILE_PATH); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); char *atkeystr = NULL; @@ -87,7 +87,7 @@ exit: { atclient_atkeys_free(&atkeys); atclient_atkey_free(&atkey); atclient_free(&atclient); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); free(atkeystr); return ret; } diff --git a/examples/desktop/reconnection/main.c b/examples/desktop/reconnection/main.c index 4b5ee411..52df3419 100644 --- a/examples/desktop/reconnection/main.c +++ b/examples/desktop/reconnection/main.c @@ -25,8 +25,8 @@ int main() { atclient_atkeys atkeys; atclient_atkeys_init(&atkeys); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); if ((ret = atclient_utils_populate_atkeys_from_homedir(&atkeys, ATSIGN)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to set up atkeys: %d\n", ret); @@ -62,7 +62,7 @@ int main() { exit: { atclient_free(&atclient1); atclient_atkeys_free(&atkeys); - atclient_pkam_authenticate_options_free(&options); + atclient_authenticate_options_free(&options); return ret; } } diff --git a/examples/desktop/repl/src/main.c b/examples/desktop/repl/src/main.c index db75d710..11cf71b6 100644 --- a/examples/desktop/repl/src/main.c +++ b/examples/desktop/repl/src/main.c @@ -24,7 +24,7 @@ * --key-file [~/.atsign/keys/@atsign_key.atKeys] */ -static int set_up_pkam_auth_options(atclient_pkam_authenticate_options *pkam_authenticate_options, +static int set_up_pkam_auth_options(atclient_authenticate_options *pkam_authenticate_options, const char *root_url); static int start_repl_loop(atclient *atclient, repl_args *repl_args); @@ -42,8 +42,8 @@ int main(int argc, char *argv[]) { atclient_atkeys atkeys; atclient_atkeys_init(&atkeys); - atclient_pkam_authenticate_options pkam_authenticate_options; - atclient_pkam_authenticate_options_init(&pkam_authenticate_options); + atclient_authenticate_options pkam_authenticate_options; + atclient_authenticate_options_init(&pkam_authenticate_options); atclient atclient; atclient_init(&atclient); @@ -91,13 +91,13 @@ int main(int argc, char *argv[]) { exit: { repl_args_free(&repl_args); atclient_atkeys_free(&atkeys); - atclient_pkam_authenticate_options_free(&pkam_authenticate_options); + atclient_authenticate_options_free(&pkam_authenticate_options); atclient_free(&atclient); return ret; } } -static int set_up_pkam_auth_options(atclient_pkam_authenticate_options *pkam_authenticate_options, +static int set_up_pkam_auth_options(atclient_authenticate_options *pkam_authenticate_options, const char *root_url) { int ret = 1; @@ -133,12 +133,12 @@ static int set_up_pkam_auth_options(atclient_pkam_authenticate_options *pkam_aut goto exit; } - if ((ret = atclient_pkam_authenticate_options_set_at_directory_host(pkam_authenticate_options, root_host)) != 0) { + if ((ret = atclient_authenticate_options_set_at_directory_host(pkam_authenticate_options, root_host)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to set at directory host\n"); goto exit; } - if ((ret = atclient_pkam_authenticate_options_set_at_directory_port(pkam_authenticate_options, root_port)) != 0) { + if ((ret = atclient_authenticate_options_set_at_directory_port(pkam_authenticate_options, root_port)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to set at directory port\n"); goto exit; } diff --git a/examples/desktop/send_enroll_request/CMakeLists.txt b/examples/desktop/send_enroll_request/CMakeLists.txt new file mode 100644 index 00000000..a5cd8604 --- /dev/null +++ b/examples/desktop/send_enroll_request/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.19) + +project(send_enroll_request LANGUAGES C VERSION 0.0.1) + +add_executable(main ${CMAKE_CURRENT_LIST_DIR}/src/main.c) + +find_package(atsdk CONFIG REQUIRED) + +target_link_libraries(main PRIVATE atsdk::atclient atsdk::atchops atsdk::atcommons atsdk::atauth) + diff --git a/examples/desktop/send_enroll_request/develop.sh b/examples/desktop/send_enroll_request/develop.sh new file mode 100755 index 00000000..2d4164b9 --- /dev/null +++ b/examples/desktop/send_enroll_request/develop.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -eu +FULL_PATH_TO_SCRIPT="$(realpath "${BASH_SOURCE[0]}")" +SCRIPT_DIRECTORY="$(dirname "$FULL_PATH_TO_SCRIPT")" +cd "$SCRIPT_DIRECTORY/../../../packages/atclient" +cmake -S . -B build +sudo cmake --build build --target install +pwd +cd "$SCRIPT_DIRECTORY" +cmake -S . -B build +cmake --build build --target all +echo "Running main:" +echo "" +echo "" +cd build && ./main +cd .. diff --git a/examples/desktop/send_enroll_request/src/main.c b/examples/desktop/send_enroll_request/src/main.c new file mode 100644 index 00000000..30fa8ed8 --- /dev/null +++ b/examples/desktop/send_enroll_request/src/main.c @@ -0,0 +1,71 @@ +#include "atclient/atclient.h" +#include "atcommons/enroll_status.h" +#include "atlogger/atlogger.h" +#include "atcommons/enroll_namespace.h" +#include "atcommons/enroll_params.h" +#include "atauth/send_enroll_request.h" +#include "atchops/base64.h" +#include +#include +#include + +#define TAG "send_enroll_req_example" +int main() { + atclient client; + atclient_init(&client); + + enroll_namespace_t namespace1 = {"kingslanding", "rw"}; + enroll_namespace_t namespace2 = {"winterfell", "r"}; + + // Allocate memory for ns_list with initial size for 2 namespaces + enroll_namespace_list_t *ns_list = malloc(sizeof(enroll_namespace_list_t) + sizeof(enroll_namespace_t *) * 2); + if (!ns_list) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for namespace list\n"); + return -1; + } + memset(ns_list, 0, sizeof(enroll_namespace_list_t)); + ns_list->length = 0; + + // Append namespaces to ns_list + int ret = atcommons_enroll_namespace_list_append(&ns_list, &namespace1); + + ret = atcommons_enroll_namespace_list_append(&ns_list, &namespace2); + + ret = atcommons_enroll_namespace_list_append(&ns_list, &(enroll_namespace_t){"riverlands", "rw"}); + + // Allocate and initialize enroll_params_t + enroll_params_t *params = malloc(sizeof(enroll_params_t)); + if (!params) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for enroll_params_t\n"); + free(ns_list); + return -1; + } + atcommons_enroll_params_init(params); + + // Assign parameters + params->app_name = "test-app"; + params->device_name = "test-device"; + params->otp = "XYZABC"; + params->ns_list = ns_list; + params->apkam_keys_expiry_in_millis = 1000; + + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Initialization success\n"); + + // Allocate memory for enroll_id and send the enroll request + char enroll_id[ENROLL_ID_MAX_LEN]; + char enroll_status[ENROLL_STATUS_STRING_MAX_LEN]; + + ret = atauth_send_enroll_request(&client, params, enroll_id, enroll_status); + printf("Final ret: %d\n", ret); + if (ret == 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Enroll ID: %s\tEnroll status: %s\n", enroll_id, enroll_status); + } else { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Enroll request failed\n"); + } + + // Clean up + free(ns_list); + free(params); + + return ret; +} diff --git a/packages/atauth/CMakeLists.txt b/packages/atauth/CMakeLists.txt new file mode 100644 index 00000000..19fee328 --- /dev/null +++ b/packages/atauth/CMakeLists.txt @@ -0,0 +1,150 @@ +# Configurable options +option(ATAUTH_BUILD_TESTS "Build tests for atauth" OFF) +option(ATAUTH_BUILD_EXECUTABLES "Build executables in atauth" ON) + +# Set include directory and file sources +set (ATAUTH_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include) +set (ATAUTH_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/send_enroll_request.c + ${CMAKE_CURRENT_LIST_DIR}/src/atactivate_arg_parser.c + ${CMAKE_CURRENT_LIST_DIR}/src/atactivate.c + ${CMAKE_CURRENT_LIST_DIR}/src/atauth_build_atkeys_file_path.c + ${CMAKE_CURRENT_LIST_DIR}/src/atauth_fetch_home_dir.c +) + +# Project setup +cmake_minimum_required(VERSION 3.24) +set(CMAKE_C_STANDARD 99) +cmake_policy(SET CMP0135 NEW) + +## not adding the esp target yet + +project( + atauth + VERSION 0.0.1 + DESCRIPTION "Atsign technology authentication library" + HOMEPAGE_URL https://atsign.com + LANGUAGES C +) + +if(NOT ESP_PLATFORM) + include(GNUInstallDirs) + + # Determine if atchops is being built as a subproject using add_subdirectory() + if(NOT DEFINED ATAUTH_AS_SUBPROJECT) + set(ATAUTH_AS_SUBPROJECT ON) + + if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(ATAUTH_AS_SUBPROJECT OFF) + endif () + endif () + + message(STATUS "[ATAUTH] ATAUTH_AS_SUBPROJECT: ${ATAUTH_AS_SUBPROJECT}") + + # Import cjson + if (NOT TARGET cjson) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/find_cjson.cmake) + endif () + + # Import mbedtls + if(NOT TARGET mbedcrypto OR NOT TARGET everest OR NOT TARGET p256m) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/find_mbedtls.cmake) + endif() + + # Import atlogger + if (NOT TARGET atlogger) + set(atlogger_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../atlogger) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/atlogger.cmake) + endif () + + # Import atcommons + if(NOT TARGET atcommons) + set(atcommons_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../atcommons) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/atcommons.cmake) + endif () + + # Import atclient + if(NOT TARGET atclient) + set(atclient_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../atclient) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/atclient.cmake) + endif () + + # Create library targets + add_library(${PROJECT_NAME} STATIC ${ATAUTH_SOURCES}) + add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + + # LINK + # Link include headers to library targets + target_include_directories( + ${PROJECT_NAME} + PUBLIC + $ + $ + $ + ) + + set( + ATAUTH_INSTALL_TARGETS + cjson + mbedtls + mbedx509 + mbedcrypto + everest + p256m + uuid4-static + atclient + atcommons + atlogger + atchops + ) + target_link_libraries(${PROJECT_NAME} PUBLIC ${ATAUTH_INSTALL_TARGETS}) + + # INSTALL + # Install the include headers + install( + DIRECTORY ${ATAUTH_INCLUDE_DIR}/${PROJECT_NAME} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install( + FILES ${cJSON_SOURCE_DIR}/cJSON.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + # Install libraries to config target + install( + TARGETS ${PROJECT_NAME} ${ATAUTH_INSTALL_TARGETS} + EXPORT ${PROJECT_NAME}-config + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + + # Build atactivate executable + if (ATAUTH_BUILD_EXECUTABLES) + add_executable(atactivate ${CMAKE_CURRENT_LIST_DIR}/src/atactivate.c) + target_link_libraries(atactivate PRIVATE cjson atlogger atcommons atchops atclient atauth) + endif () + + # EXPORT + if (NOT ATAUTH_AS_SUBPROJECT) + # install as a config.make + install( + EXPORT ${PROJECT_NAME}-config + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + FILE ${PROJECT_NAME}-config.cmake + ) + + #export the config.cmake + export( + EXPORT ${PROJECT_NAME}-config + NAMESPACE ${PROJECT_NAME}:: + FILE ${PROJECT_NAME}-config.cmake + ) + endif () + + # Build the tests - No tests for ATAUTH yet + # if(ATAUTH_BUILD_TESTS) + # enable_testing() + # add_subdirectory(tests) + # endif() +endif () \ No newline at end of file diff --git a/packages/atauth/include/atauth/atactivate_arg_parser.h b/packages/atauth/include/atauth/atactivate_arg_parser.h new file mode 100644 index 00000000..17646259 --- /dev/null +++ b/packages/atauth/include/atauth/atactivate_arg_parser.h @@ -0,0 +1,25 @@ +#ifndef ATACTIVATE_ARG_PARSER_H +#define ATACTIVATE_ARG_PARSER_H + +/** + * @brief Parses command-line arguments to initialize the atactivate + * configuration + * + * Note: Memory need not be preallocated for atsign, cram_secret, atkeys_fp, first_app_name, first_device_name, + * root_host and root_port. Caller needs to free the above mentioned variables + * after use + * + * @param argc The number of arguments + * @param argv The array of arguments + * @param atsign pointer to store the atsign value + * @param cram_secret pointer to store the cram_secret value + * @param otp + * @param atkeys_fp pointer to store the file path of the atkeys + * @param root_host pointer to store the root host server address + * @param root_port pointer to store the root port value + * @return int 0 on success, non-zero on error + */ +int atactivate_parse_args(int argc, char *argv[], char **atsign, char **cram_secret, char **otp, char **atkeys_fp, + char **root_host, int *root_port); + +#endif // ATACTIVATE_ARG_PARSER_H diff --git a/packages/atauth/include/atauth/atauth_build_atkeys_file_path.h b/packages/atauth/include/atauth/atauth_build_atkeys_file_path.h new file mode 100644 index 00000000..c962e77b --- /dev/null +++ b/packages/atauth/include/atauth/atauth_build_atkeys_file_path.h @@ -0,0 +1,13 @@ +#ifndef ATAUTH_BUILD_ATKEYS_FILE_PATH_H +#define ATAUTH_BUILD_ATKEYS_FILE_PATH_H + +/** + * @brief Constructs the default atkeys file path for the given atsign. [Default path: $HOME/.atsign/keys/@atsign_key.atKeys] + * + * @param atkeys_path Pointer to store the null-terminated atkeys filepath (memory will be allocated by method) + * @param atsign Pointer to atsign string + * @return int 0 on success, non-zero on error + */ +int atauth_build_atkeys_file_path(char **atkeys_path, const char *atsign); + +#endif //ATAUTH_BUILD_ATKEYS_FILE_PATH_H diff --git a/packages/atauth/include/atauth/atauth_fetch_home_dir.h b/packages/atauth/include/atauth/atauth_fetch_home_dir.h new file mode 100644 index 00000000..cc9db16a --- /dev/null +++ b/packages/atauth/include/atauth/atauth_fetch_home_dir.h @@ -0,0 +1,15 @@ +#ifndef ATAUTH_FETCH_HOME_DIR_H +#define ATAUTH_FETCH_HOME_DIR_H + +/** + * @brief fetches the home directory of the current user (platform independent) + * + * @param home_dir A buffer where the home directory path will be stored. Memory will be allocated by the method. + * + * Note: path always has a trailing seperator ('/' or '\\' based on platform) + * + * @return 0 on success, non-zero on failure. + */ +int atauth_get_home_directory(char **home_dir); + +#endif // ATAUTH_FETCH_HOME_DIR_H \ No newline at end of file diff --git a/packages/atauth/include/atauth/send_enroll_request.h b/packages/atauth/include/atauth/send_enroll_request.h new file mode 100644 index 00000000..c2b02045 --- /dev/null +++ b/packages/atauth/include/atauth/send_enroll_request.h @@ -0,0 +1,23 @@ +#ifndef ATAUTH_SEND_ENROLL_REQUEST +#define ATAUTH_SEND_ENROLL_REQUEST + +#include +#include + +#define ENROLL_ID_MAX_LEN 50 + +/** + * @brief Sends an enrollment request to the server. Then parses and returns the enrollment ID and status. + * +* + * @param client Pointer to an authenticated instance of atclient + * @param ep Pointer to the `enroll_params_t` structure containing enrollment request parameters + * @param enroll_id buffer where the enrollment ID will be stored. Memory should be allocated by caller. + * Allocation size should be ENROLL_ID_MAX_LEN + * @param enroll_status Pointer to a buffer where the enrollment status will be stored + * + * @returns 0 on success, non-zero error code on failure. + */ +int atauth_send_enroll_request(atclient *client, const atcommons_enroll_params_t *ep, char *enroll_id, char *enroll_status); + +#endif \ No newline at end of file diff --git a/packages/atauth/src/atactivate.c b/packages/atauth/src/atactivate.c new file mode 100644 index 00000000..03101fe8 --- /dev/null +++ b/packages/atauth/src/atactivate.c @@ -0,0 +1,406 @@ +#include "atauth/atactivate_arg_parser.h" +#include "atauth/atauth_build_atkeys_file_path.h" +#include "atchops/base64.h" +#include "atclient/atclient.h" +#include "atclient/atkeys.h" +#include "atclient/connection.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TAG "atactivate" +#define DEFAULT_FIRST_APP_NAME "firstApp" +#define DEFAULT_FIRST_DEVICE_NAME "firstDevice" +#define AES_256_KEY_BYTES 32 +#define RSA_2048_PRIVKEY_BYTES 1300 // in PKCS#8 format includes padding + +int main(int argc, char *argv[]) { + atlogger_set_logging_level(ATLOGGER_LOGGING_LEVEL_INFO); + int ret = 0; + char *atsign = NULL, *cram_secret = NULL, *root_host = NULL, *atkeys_fp = NULL, *otp = NULL; + int *root_port = NULL; + char enrollment_id[ENROLL_ID_MAX_LEN]; + char status[ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN]; + + // intialize iv used for aes encryption of keys + unsigned char *iv = malloc(sizeof(unsigned char) * ATCHOPS_IV_BUFFER_SIZE); + + // initialize apkam symmetric key and self encryption key (bytes) + unsigned char *self_encryption_key_bytes, *apkam_symmetric_key_bytes; + size_t aes256_key_unsigned_char_bytes_size = sizeof(unsigned char) * AES_256_KEY_BYTES; + self_encryption_key_bytes = malloc(aes256_key_unsigned_char_bytes_size); + apkam_symmetric_key_bytes = malloc(aes256_key_unsigned_char_bytes_size); + + // initialize base64 encoded apkam symmetric key and self encryption key + size_t aes_key_base64_size = atchops_base64_encoded_size(aes256_key_unsigned_char_bytes_size); + size_t aes256_key_unsigned_char_base64_size = sizeof(unsigned char) * aes_key_base64_size; + unsigned char *self_encryption_key_base64 = malloc(aes256_key_unsigned_char_base64_size); + unsigned char *apkam_symmetric_key_base64 = malloc(aes256_key_unsigned_char_base64_size); + + // intialize encrypted APKAM symmetric Key and encrypted default encryption private key (bytes) + const size_t rsa_2048_privkey_base64_len = atchops_base64_encoded_size(RSA_2048_PRIVKEY_BYTES); + const size_t aes256_encrypted_rsa_privkey_size = atchops_aes_ctr_ciphertext_size( + rsa_2048_privkey_base64_len); // size for an AES256 encrypted RSA2048 privkey in bytes + const size_t aes256_encrypted_rsa_privkey_unsigned_char_size = + sizeof(unsigned char) * aes256_encrypted_rsa_privkey_size; + const size_t aes256_encrypted_aes256_key_size = atchops_aes_ctr_ciphertext_size( + aes_key_base64_size); // size of AES256 key encrypted with another AES256 key(bytes) + const size_t aes256_encrypted_aes256_key_unsigned_char_size = + sizeof(unsigned char) * aes256_encrypted_aes256_key_size; + unsigned char *encrypted_default_encryption_private_key = malloc(aes256_encrypted_rsa_privkey_unsigned_char_size); + unsigned char *encrypted_self_encryption_key = malloc(aes256_encrypted_aes256_key_unsigned_char_size); + + // intialize base64 encoded encrypted APKAM symmetric Key and encrypted default encryption private key + const size_t aes256_encrypted_rsa_2048_privkey_base64_len = atchops_base64_encoded_size(rsa_2048_privkey_base64_len); + const size_t aes256_encrypted_aes_key_base64_len = + atchops_base64_encoded_size(atchops_base64_encoded_size(ATCHOPS_AES_256)); + unsigned char *encrypted_self_encryption_key_base64 = + malloc(sizeof(unsigned char) * aes256_encrypted_aes_key_base64_len); + unsigned char *encrypted_default_encryption_private_key_base64 = + malloc(sizeof(unsigned char) * aes256_encrypted_rsa_2048_privkey_base64_len); + + // allocate memory for enroll params + atcommons_enroll_params_t *ep = malloc(sizeof(atcommons_enroll_params_t)); // Allocate enrollment params + + // ensure all the above memory allocations hold + if (iv == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate mem for iv buffer\n"); + ret = -1; + goto exit; + } + if (self_encryption_key_bytes == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate mem for self_encryption_key_bytes buffer\n"); + ret = -1; + goto iv_exit; + } + if (apkam_symmetric_key_bytes == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate mem for apkam_symmetric_key_bytes buffer\n"); + ret = -1; + goto self_enc_key_bytes_exit; + } + if (self_encryption_key_base64 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate mem for self_encryption_key_base64 buffer\n"); + ret = -1; + goto aes_keys_bytes_exit; + } + if (apkam_symmetric_key_base64 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate mem for apkam_symmetric_key_base64 buffer\n"); + ret = -1; + goto aes_keys_bytes_exit; + } + if (encrypted_default_encryption_private_key == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Could not allocate mem for encrypted_default_encryption_private_key buffer\n"); + ret = -1; + goto aes_keys_bytes_exit; + } + if (encrypted_self_encryption_key == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Could not allocate mem for encrypted_self_encryption_key buffer\n"); + ret = -1; + goto enc_def_enc_privkey_exit; + } + if (encrypted_default_encryption_private_key_base64 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Could not allocate mem for encrypted_default_encryption_private_key_base64 buffer\n"); + ret = -1; + goto enc_self_enc_key_exit; + } + if (encrypted_self_encryption_key_base64 == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Could not allocate mem for encrypted_self_encryption_key_base64 buffer\n"); + ret = -1; + goto enc_def_enc_privkey_base64_exit; + } + if (ep == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate memory for enroll params\n"); + ret = -1; + goto enc_self_enc_key_base64_exit; + } + + memset(iv, 0, sizeof(unsigned char) * ATCHOPS_IV_BUFFER_SIZE); + memset(self_encryption_key_bytes, 0, aes256_key_unsigned_char_bytes_size); + memset(apkam_symmetric_key_bytes, 0, aes256_key_unsigned_char_bytes_size); + memset(self_encryption_key_base64, 0, aes256_key_unsigned_char_base64_size); + memset(apkam_symmetric_key_base64, 0, aes256_key_unsigned_char_base64_size); + memset(encrypted_default_encryption_private_key, 0, aes256_encrypted_rsa_privkey_unsigned_char_size); + memset(encrypted_self_encryption_key, 0, aes256_encrypted_aes256_key_unsigned_char_size); + memset(encrypted_default_encryption_private_key_base64, 0, + sizeof(unsigned char) * aes256_encrypted_rsa_2048_privkey_base64_len); + memset(encrypted_self_encryption_key_base64, 0, sizeof(unsigned char) * aes256_encrypted_aes_key_base64_len); + memset(ep, 0, sizeof(atcommons_enroll_params_t)); + + /* + * 1. Parse args + */ + if ((ret = atactivate_parse_args(argc, argv, &atsign, &cram_secret, &otp, &atkeys_fp, &root_host, root_port)) != 0) { + goto exit; + } + // 1.1 if atkeys filepath was not passed through args, build default atkeys file path + if (atkeys_fp == NULL) { + if ((ret = atauth_build_atkeys_file_path(&atkeys_fp, atsign)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not build atkeys filepath\n"); + ret = -1; + goto args_exit; + } + } + + /* + * 2. init atclient and CRAM auth + */ + atclient at_client; + atclient_init(&at_client); + + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); + + if ((ret = atclient_cram_authenticate(&at_client, atsign, cram_secret, &options)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "CRAM authentication failed\n"); + goto atclient_exit; + } + + /* + * 3. Generate APKAM keypair + Default Encryption Keypair + Self encryption key + APKAM Symmetric Key + */ + atclient_atkeys atkeys; + atclient_atkeys_init(&atkeys); + + // 3.1 Generate APKAM Keypair - RSA2048 + unsigned char *pkam_public_key_base64 = NULL, *pkam_private_key_base64 = NULL; + if ((ret = atchops_rsa_key_generate_base64(&pkam_public_key_base64, &pkam_private_key_base64)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed APKAM Keypair Generation\n"); + goto atkeys_free_exit; + } + // set base64 pkam public and private key in the atkeys struct + atclient_atkeys_set_pkam_public_key_base64(&atkeys, (const char *)pkam_public_key_base64, + strlen((const char *)pkam_public_key_base64)); + atclient_atkeys_set_pkam_private_key_base64(&atkeys, (const char *)pkam_private_key_base64, + strlen((const char *)pkam_private_key_base64)); + // populate the pkam public/private key bytes in the atkeys struct from base64 format + atclient_atkeys_populate_pkam_public_key(&atkeys, (const char *)pkam_public_key_base64, + strlen((const char *)pkam_public_key_base64)); + atclient_atkeys_populate_pkam_private_key(&atkeys, (const char *)pkam_private_key_base64, + strlen((const char *)pkam_private_key_base64)); + + // 3.2 Generate Default Encryption Keypair - RSA2048 + unsigned char *encrypt_public_key_base64 = NULL, *encrypt_private_key_base64 = NULL; + if ((ret = atchops_rsa_key_generate_base64(&encrypt_public_key_base64, &encrypt_private_key_base64)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed Default Encryption Keypair Generation\n"); + goto pkam_keypair_free_exit; + } + // sets base64 public and private key in the atkeys struct + atclient_atkeys_set_encrypt_public_key_base64(&atkeys, (const char *)encrypt_public_key_base64, + strlen((const char *)encrypt_public_key_base64)); + atclient_atkeys_set_encrypt_private_key_base64(&atkeys, (const char *)encrypt_private_key_base64, + strlen((const char *)encrypt_private_key_base64)); + // populate the encryption public/private key bytes in the atkeys struct from base64 format + atclient_atkeys_populate_encrypt_public_key(&atkeys, (const char *)encrypt_public_key_base64, + strlen((const char *)encrypt_public_key_base64)); + atclient_atkeys_populate_encrypt_private_key(&atkeys, (const char *)encrypt_private_key_base64, + strlen((const char *)encrypt_private_key_base64)); + + // 3.3 Generate Self Encryption Key - AES256 + if ((ret = atchops_aes_generate_key(self_encryption_key_bytes, ATCHOPS_AES_256)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed Self Encryption Key Generation | ret: %d\n", ret); + goto def_enc_keypair_free_exit; + } + + // 3.3.1 base64 encode the SelfEncryptionKey + populate the same into atkeys struct + size_t self_enc_key_base64_len = 0; + if ((ret = atchops_base64_encode(self_encryption_key_bytes, aes256_key_unsigned_char_bytes_size, + self_encryption_key_base64, aes256_key_unsigned_char_base64_size, + &self_enc_key_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed encoding SelfEncryptionKey to base64 | ret: %d\n", ret); + goto def_enc_keypair_free_exit; + } + atclient_atkeys_set_self_encryption_key_base64(&atkeys, (const char *)self_encryption_key_base64, + self_enc_key_base64_len); + + // 3.4 Generate APKAM Symmetric Key - AES256 + if ((ret = atchops_aes_generate_key(apkam_symmetric_key_bytes, ATCHOPS_AES_256)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed APKAM SymmetricKey Generation\n"); + goto def_enc_keypair_free_exit; + } + + // 3.4.1 base64 encoding the APKAM symmetric key + populate the same into atkeys struct + size_t apkam_symm_key_base64_len = 0; + if ((ret = atchops_base64_encode(apkam_symmetric_key_bytes, aes256_key_unsigned_char_bytes_size, + apkam_symmetric_key_base64, aes256_key_unsigned_char_base64_size, + &apkam_symm_key_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed encoding APKAM SymmetricKey to base64\n"); + goto def_enc_keypair_free_exit; + } + atclient_atkeys_set_apkam_symmetric_key_base64(&atkeys, (const char *)apkam_symmetric_key_base64, + apkam_symm_key_base64_len); + + /* + * 4. Encrypt the keys and send the onboarding enrollment request + */ + // 4.1 Encrypt default_encryption_private_key with APKAM Symmetric Key + size_t encrypted_def_encrypt_private_key_len = 0; + if ((ret = atchops_aes_ctr_encrypt( + apkam_symmetric_key_bytes, ATCHOPS_AES_256, iv, encrypt_private_key_base64, + strlen((char *)encrypt_private_key_base64), encrypted_default_encryption_private_key, + aes256_encrypted_rsa_privkey_unsigned_char_size, &encrypted_def_encrypt_private_key_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "AES encrypt default_encryption_private_key failed | ret: %d\n", + ret); + goto def_enc_keypair_free_exit; + } + + // 4.1.1 Base64 encode the encrypted_default_encryption_private_key + size_t encrypted_default_encryption_private_key_base64_len = 0; + if ((ret = atchops_base64_encode(encrypted_default_encryption_private_key, encrypted_def_encrypt_private_key_len, + encrypted_default_encryption_private_key_base64, + sizeof(unsigned char) * aes256_encrypted_rsa_2048_privkey_base64_len, + &encrypted_default_encryption_private_key_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "base64 encode encrypted_default_encryption_private_key failed | ret: %d\n", ret); + goto def_enc_keypair_free_exit; + } + + // 4.2 Encrypt self_encryption_key with APKAM Symmetric Key + size_t encrypted_self_encrypt_key_len = 0; + if ((ret = atchops_aes_ctr_encrypt(apkam_symmetric_key_bytes, ATCHOPS_AES_256, iv, self_encryption_key_base64, + strlen((const char *)self_encryption_key_base64), encrypted_self_encryption_key, + aes256_encrypted_aes256_key_unsigned_char_size, + &encrypted_self_encrypt_key_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "AES encrypt self_encryption_key failed\tret: %d\n", ret); + goto def_enc_keypair_free_exit; + } + + // 4.2.1 Base64 encode the encrypted_self_encryption_key + size_t encrypted_self_encryption_key_base64_len = 0; + if ((ret = atchops_base64_encode(encrypted_self_encryption_key, encrypted_self_encrypt_key_len, + encrypted_self_encryption_key_base64, + sizeof(unsigned char) * aes256_encrypted_aes_key_base64_len, + &encrypted_self_encryption_key_base64_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "base64 encode encrypted_self_encryption_key failed\tret: %d\n", + ret); + goto def_enc_keypair_free_exit; + } + + // 4.3 Initialize enrollment params + atcommons_enroll_params_init(ep); + ep->app_name = DEFAULT_FIRST_APP_NAME; + ep->device_name = DEFAULT_FIRST_DEVICE_NAME; + ep->apkam_public_key = (unsigned char *)atkeys.pkam_public_key_base64; + ep->encrypted_default_encryption_private_key = encrypted_default_encryption_private_key_base64; + ep->encrypted_self_encryption_key = encrypted_self_encryption_key_base64; + + // 4.4 Send onboarding enrollment request + if ((ret = atauth_send_enroll_request(&at_client, ep, enrollment_id, status)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atauth_send_enroll_request: %d\n", ret); + goto def_enc_keypair_free_exit; + } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "MPKAM enrollment response:\tenrollment_id: %s\tstatus: %s\n", + enrollment_id, status); + + // 4.5 Populate MPKAM enrollment_id into atkeys struct + atclient_atkeys_set_enrollment_id(&atkeys, enrollment_id, sizeof(enrollment_id)); + + /* + * 5. Close existing atclient connection + */ + atclient_connection_disconnect(&at_client.atserver_connection); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "Terminated existing atserver connection\n"); + /* + * 6. Perform PKAM auth + */ + if ((ret = atclient_pkam_authenticate(&at_client, atsign, &atkeys, &options)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "PKAM auth failed | atclient_pkam_authenticate: %d\n", ret); + goto atclient_exit; + } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "PKAM auth success\n"); + + /* + * 7. Update Default Encryption Public Key to server + */ + atclient_atkey def_enc_pub_atkey; + atclient_atkey_init(&def_enc_pub_atkey); + + if ((ret = atclient_atkey_create_public_key(&def_enc_pub_atkey, "publickey", atsign, NULL)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to create public key\n"); + goto enc_pub_key_free_exit; + } + atclient_atkey_metadata_set_is_public(&def_enc_pub_atkey.metadata, true); + + if ((ret = atclient_put_public_key(&at_client, &def_enc_pub_atkey, atkeys.encrypt_private_key_base64, NULL, NULL)) != + 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "Failed to updating enc_public_key to server | atclient_put_public_key: %d\n", ret); + goto enc_pub_key_free_exit; + } + + /* + * 8. Delete CRAM secret from the server + */ + atclient_atkey cram_atkey; + atclient_atkey_init(&cram_atkey); + + if ((ret = atclient_atkey_create_reserved_key(&cram_atkey, "privatekey:at_secret")) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed creating reserved_key: at_secret\n"); + goto cram_atkey_free_exit; + } + + atclient_delete_request_options delete_request_options; + atclient_delete_request_options_init(&delete_request_options); + // skips is_atclient_atkey_is_shared_by_initialized check + atclient_delete_request_options_set_skip_shared_by_check(&delete_request_options, true); + if ((ret = atclient_delete(&at_client, &cram_atkey, &delete_request_options, NULL)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed deleting CRAM Secret\n"); + goto cram_atkey_free_exit; + } + + /* + * 9. Write the keys to the .atKeys file + */ + if ((ret = atclient_atkeys_write_to_path(&atkeys, atkeys_fp)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_atkeys_write_to_path: %d\n", ret); + ret = 1; + goto cram_atkey_free_exit; + } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Success !!!\t Your atKeys file has been generated at \'%s\'\n", + atkeys_fp); + + // exits +cram_atkey_free_exit: { atclient_atkey_free(&cram_atkey); } +enc_pub_key_free_exit: { atclient_atkey_free(&def_enc_pub_atkey); } +def_enc_keypair_free_exit: { + free(encrypt_public_key_base64); + free(encrypt_private_key_base64); +} +pkam_keypair_free_exit: { + free(pkam_public_key_base64); + free(pkam_private_key_base64); +} +atkeys_free_exit: { atclient_atkeys_free(&atkeys); } +atclient_exit: { + atclient_authenticate_options_free(&options); + atclient_free(&at_client); +} +atkeys_fp_exit: { free(atkeys_fp); } +args_exit: { + free(atsign); + free(cram_secret); + free(root_host); +} +enroll_params_exit: { free(ep); } +enc_self_enc_key_base64_exit: { free(encrypted_self_encryption_key_base64); } +enc_def_enc_privkey_base64_exit: { free(encrypted_default_encryption_private_key_base64); } +enc_self_enc_key_exit: { free(encrypted_self_encryption_key); } +enc_def_enc_privkey_exit: { free(encrypted_default_encryption_private_key); } +aes_keys_bytes_exit: { free(apkam_symmetric_key_bytes); } +self_enc_key_bytes_exit: { free(self_encryption_key_bytes); } +iv_exit: { free(iv); } +exit: { + if (ret != 0) + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Aborting with exit code: %d\n", ret); + exit(ret); +} +} \ No newline at end of file diff --git a/packages/atauth/src/atactivate_arg_parser.c b/packages/atauth/src/atactivate_arg_parser.c new file mode 100644 index 00000000..80de3f7e --- /dev/null +++ b/packages/atauth/src/atactivate_arg_parser.c @@ -0,0 +1,104 @@ +#include "atauth/atactivate_arg_parser.h" +#include +#include +#include +#include + +#define DEFAULT_ROOT_SERVER "root.atsign.org" +#define DEFAULT_ROOT_PORT 64 + +int atactivate_parse_args(int argc, char *argv[], char **atsign, char **cram_secret, char **otp, char **atkeys_fp, + char **root_host, int *root_port) { + int ret = 0; + int opt; + + // Initialize defaults + *root_host = malloc(sizeof(char) * strlen(DEFAULT_ROOT_SERVER) + 1); + if (*root_host == NULL) { + fprintf(stderr, "Memory allocation failed for root_host\n"); + return -1; + } + strcpy(*root_host, DEFAULT_ROOT_SERVER); + root_port = malloc(sizeof(int)); + if (root_port == NULL) { + fprintf(stderr, "Memory allocation failed for root_port\n"); + return -1; + } + *root_port = DEFAULT_ROOT_PORT; + + // Parse command-line arguments + while ((opt = getopt(argc, argv, "a:c:k:o:r:p:h")) != -1) { + switch (opt) { + case 'a': + *atsign = malloc(sizeof(char) * strlen(optarg) + 1); + if (*atsign == NULL) { + fprintf(stderr, "Memory allocation failed for atsign\n"); + ret = -1; + goto exit; + } + strcpy(*atsign, optarg); + break; + case 'c': + *cram_secret = malloc(sizeof(char) * strlen(optarg) + 1); + if (*cram_secret == NULL) { + fprintf(stderr, "Memory allocation failed for cram_secret\n"); + ret = -1; + goto exit; + } + strcpy(*cram_secret, optarg); + break; + case 'k': + *atkeys_fp = malloc(sizeof(char) * strlen(optarg) + 1); + if (*atkeys_fp == NULL) { + fprintf(stderr, "Memory allocation failed for atkeys file path\n"); + ret = -1; + goto exit; + } + strcpy(*atkeys_fp, optarg); + break; + case 'o': + *otp = malloc(sizeof(char) * strlen(optarg)); + if(*otp == NULL) { + fprintf(stderr, "Memory allocation failed for atkeys file path\n"); + ret = -1; + goto exit; + } + strcpy(*otp, optarg); + break; + case 'r': + *root_host = realloc(*root_host, sizeof(char) * strlen(optarg) + 1); + if (*root_host == NULL) { + fprintf(stderr, "Memory reallocation failed for root_host\n"); + ret = -1; + goto exit; + } + strcpy(*root_host, optarg); + break; + case 'p': + *root_port = atoi(optarg); + break; + case 'h': + fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); + exit(0); // force exit to display usage + default: + fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); + ret = -1; + goto exit; + } + } + + if (*atsign == NULL) { + fprintf(stderr, "Error: -a (atsign) is mandatory.\n"); + fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); + ret = 1; + } + + if(*cram_secret == NULL && *otp == NULL) { + fprintf(stderr, "Cannot proceed without either of CRAM secret on enroll OTP.\n"); + fprintf(stderr, "Usage: %s -a atsign -c cram-secret -o otp [-r root-server] [-p port]\n", argv[0]); + ret = 1; + } + +exit: + return ret; +} diff --git a/packages/atauth/src/atauth_build_atkeys_file_path.c b/packages/atauth/src/atauth_build_atkeys_file_path.c new file mode 100644 index 00000000..e82f3af2 --- /dev/null +++ b/packages/atauth/src/atauth_build_atkeys_file_path.c @@ -0,0 +1,36 @@ +#include "atauth/atauth_build_atkeys_file_path.h" +#include "atauth/atauth_fetch_home_dir.h" + +#include +#include +#include +#include + +#define DEFAULT_ATKEYS_DIR ".atsign/keys/" +#define ATKEYS_EXTENSION ".atKeys" +#define TAG "build_atkeys_filepath" + +int atauth_build_atkeys_file_path(char **atkeys_path, const char *atsign) { + int ret = 0; + char *home_dir = NULL; + + if ((ret = atauth_get_home_directory(&home_dir)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "atauth_get_home_directory: %d/n", ret); + return ret; + } + + // Calculate path length and allocate memory + const int path_len = + snprintf(NULL, 0, "%s%s%s_key%s", home_dir, DEFAULT_ATKEYS_DIR, atsign, ATKEYS_EXTENSION) + 1; // +1 for \0 + *atkeys_path = malloc(sizeof(char) * path_len); + if (*atkeys_path == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate memory for atkeys_fp\n"); + ret = -1; + goto exit; + } + + snprintf(*atkeys_path, path_len, "%s%s%s_key%s", home_dir, DEFAULT_ATKEYS_DIR, atsign, ATKEYS_EXTENSION); + +exit: + return ret; +} diff --git a/packages/atauth/src/atauth_fetch_home_dir.c b/packages/atauth/src/atauth_fetch_home_dir.c new file mode 100644 index 00000000..74444030 --- /dev/null +++ b/packages/atauth/src/atauth_fetch_home_dir.c @@ -0,0 +1,84 @@ +#include "atauth/atauth_fetch_home_dir.h" +#include "atlogger/atlogger.h" +#include +#include +#include + +// Imports for Windows +#if defined(_WIN32) || defined(_WIN64) +#include // For SHGetFolderPathA +#include +#define PATH_SEPARATOR '\\' +#define PATH_MAX 260 // Max path length for Windows (adjustable if needed) + +// Imports for Linux +#elif defined(__linux__) +#include +#include +#include +#define PATH_SEPARATOR '/' + +// Imports for other platforms +#else +#include +#include +#include +#define PATH_SEPARATOR '/' +#endif + +#define TAG "fetch_home_dir" + +int atauth_get_home_directory(char **home_dir) { + *home_dir = malloc(PATH_MAX * sizeof(char)); + if (*home_dir == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Unable to allocate memory for home_dir"); + return -1; // Memory allocation failure + } + +#if defined(_WIN32) || defined(_WIN64) + // For Windows, use USERPROFILE or SHGetFolderPath + char *home = getenv("USERPROFILE"); + if (home == NULL) { + char path[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, path))) { + strncpy(*home_dir, path, PATH_MAX - 1); + (*home_dir)[PATH_MAX - 1] = '\0'; + } else { + free(*home_dir); + return -2; + } + } else { + strncpy(*home_dir, home, PATH_MAX - 1); + (*home_dir)[PATH_MAX - 1] = '\0'; + } + +#else + // For Unix-like systems, use getenv("HOME") or getpwuid + char *home = getenv("HOME"); + if (home == NULL) { + struct passwd *pw = getpwuid(getuid()); + if (pw == NULL || pw->pw_dir == NULL) { + atlogger_log("atcommons_get_home_directory", ATLOGGER_LOGGING_LEVEL_ERROR, + "Could not get user home directory.\n"); + free(*home_dir); + return -3; // Failed to get home directory + } + strncpy(*home_dir, pw->pw_dir, PATH_MAX - 1); + } else { + strncpy(*home_dir, home, PATH_MAX - 1); + } +#endif + + const size_t len = strlen(*home_dir); + // Ensure the path ends with the separator + if ((*home_dir)[len - 1] != PATH_SEPARATOR) { + if (len < PATH_MAX - 1) { + (*home_dir)[len] = PATH_SEPARATOR; + (*home_dir)[len + 1] = '\0'; // Ensure null termination + } else { + free(*home_dir); + return -4; // Path too long to append separator + } + } + return 0; +} diff --git a/packages/atauth/src/send_enroll_request.c b/packages/atauth/src/send_enroll_request.c new file mode 100644 index 00000000..d3fb5951 --- /dev/null +++ b/packages/atauth/src/send_enroll_request.c @@ -0,0 +1,115 @@ +#include "atauth/send_enroll_request.h" + +#include "atclient/atclient.h" +#include "atclient/constants.h" +#include "atclient/string_utils.h" +#include "atcommons/enroll_command_builder.h" +#include "atcommons/enroll_operation.h" +#include "atcommons/enroll_params.h" +#include "atlogger/atlogger.h" +#include +#include +#include + +#define TAG "send_enroll_request" + +int atauth_send_enroll_request(atclient *client, const atcommons_enroll_params_t *ep, char *enroll_id, char *enroll_status) { + int ret = 0; + const size_t recv_size = 100; // to hold the response for enroll request + unsigned char recv[recv_size]; + char *recv_trimmed = NULL; + size_t recv_len; + + if (enroll_id == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "enroll_id is unallocated\n"); + ret = -1; + goto exit; + } + + /* + * 1. Fetch enroll:request command length and allocate memory + */ + const atcommons_enroll_operation_t e_op = atcommons_apkam_request; + size_t cmd_len = 0; + atcommons_build_enroll_command(NULL, 0, &cmd_len, e_op, ep); // fetch enroll_command length + const size_t cmd_size = cmd_len; + char *command = malloc(sizeof(char) * cmd_size); + if (command == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Memory allocation failed for command\n"); + ret = -1; + goto exit; + } + memset(command, 0, cmd_size); + + /* + * 2. Build enroll:request command + */ + if ((ret = atcommons_build_enroll_command(command, cmd_size, &cmd_len, e_op, ep)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not build enroll:request command\n"); + ret = -1; + goto free_command_exit; + } + if (cmd_len >= cmd_size) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "buffer overflow in enroll command buffer"); + ret = -1; + goto free_command_exit; + } + + /* + * 3. Send enroll:request command to server + */ + if ((ret = atclient_connection_send(&client->atserver_connection, (const unsigned char *)command, cmd_len, recv, + recv_size, &recv_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_connection_send: %d\n", ret); + ret = 1; + goto free_command_exit; + } + + /* + * 4. Trim + json-decode + read enrollment-id and enrollment status from the server response + */ + if ((ret = atclient_string_utils_get_substring_position((const char *)recv, ATCLIENT_DATA_TOKEN, &recv_trimmed)) != + 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "recv did not have prefix \"data:\"\n", (int)recv_len, recv); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "%s\n", recv); // log error from server + goto free_command_exit; + } + recv_trimmed += strlen(ATCLIENT_DATA_TOKEN); + recv_trimmed[recv_len - strlen(ATCLIENT_DATA_TOKEN)] = '\0'; + + cJSON *recv_json_decoded = cJSON_ParseWithLength(recv_trimmed, recv_len - strlen(ATCLIENT_DATA_TOKEN)); + if (recv_json_decoded == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to parse JSON response"); + ret = 1; + goto cjson_delete_exit; + } + + // parse and populate the enrollment id from server response + const cJSON *enroll_id_cjson = cJSON_GetObjectItemCaseSensitive(recv_json_decoded, "enrollmentId"); + if (!cJSON_IsString(enroll_id_cjson) || (enroll_id_cjson->valuestring == NULL)) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to extract enrollment_id\n"); + ret = 1; + goto cjson_delete_exit; + } + strncpy(enroll_id, enroll_id_cjson->valuestring, strlen(enroll_id_cjson->valuestring)); + enroll_id[strlen(enroll_id_cjson->valuestring)] = '\0'; + + // parse and populate enrollment status from server response + const cJSON *enroll_status_cjson = cJSON_GetObjectItemCaseSensitive(recv_json_decoded, "status"); + if (!cJSON_IsString(enroll_status_cjson) || (enroll_status_cjson->valuestring == NULL)) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to extract enroll status\n"); + ret = 1; + goto cjson_delete_exit; + } + strncpy(enroll_status, enroll_status_cjson->valuestring, strlen(enroll_status_cjson->valuestring)); + enroll_status[strlen(enroll_status_cjson->valuestring)] = '\0'; + + ret = 0; + +cjson_delete_exit: + cJSON_Delete(recv_json_decoded); +free_command_exit: + free(command); +exit: + return ret; +} diff --git a/packages/atchops/CMakeLists.txt b/packages/atchops/CMakeLists.txt index e0eff0a2..90e5f096 100644 --- a/packages/atchops/CMakeLists.txt +++ b/packages/atchops/CMakeLists.txt @@ -14,6 +14,8 @@ set( ${CMAKE_CURRENT_LIST_DIR}/src/rsa.c ${CMAKE_CURRENT_LIST_DIR}/src/sha.c ${CMAKE_CURRENT_LIST_DIR}/src/uuid.c + ${CMAKE_CURRENT_LIST_DIR}/src/hex.c + ${CMAKE_CURRENT_LIST_DIR}/src/utf8.c ) # Project setup @@ -100,8 +102,8 @@ if(NOT ESP_PLATFORM) p256m uuid4-static ) - target_link_libraries(${PROJECT_NAME} PUBLIC ${ATCHOPS_INSTALL_TARGETS}) + # INSTALL # Install the include headers install( diff --git a/packages/atchops/include/atchops/hex.h b/packages/atchops/include/atchops/hex.h new file mode 100644 index 00000000..f336a1be --- /dev/null +++ b/packages/atchops/include/atchops/hex.h @@ -0,0 +1,43 @@ +#ifndef ATCHOPS_HEX_H +#define ATCHOPS_HEX_H +#ifdef __cplusplus +extern "C" { +#endif +#include + +/** + * @brief Converts a hexadecimal string into a byte array. + * + * This function takes a string of hexadecimal characters (e.g., "1a2b3c") and + * converts it into a byte array (e.g. {0x1a, 0x2b, 0x3c}). + * + * @param bytes A pointer to a byte array where the converted values will be stored. + * @param byte_len The number of bytes to convert. This must be at least half the length of the `hex` string, + * as each byte is represented by two hexadecimal characters. + * @param hex_str A null-terminated string representing the hexadecimal value to convert. + * + * @return 0 on success, or -1 if there was an error (e.g., invalid input, insufficient byte buffer size, + * or invalid hexadecimal string). + */ +int atchops_hex_to_bytes(unsigned char *bytes, const size_t byte_len, const char *hex_str); + +/** + * @brief Converts a byte array into a hexadecimal string. + * + * This function takes an array of bytes and converts it into a string of hexadecimal + * characters (e.g., {0x1a, 0x2b, 0x3c} becomes "1a2b3c"). + * + * @param hex_str A pointer to a character array where the resulting hexadecimal string will be stored. + * The array must be large enough to hold the resulting string and a null terminator. + * @param hex_str_len The size of the `hex_str` buffer in bytes, including space for the null terminator. + * @param bytes A pointer to the byte array to convert. + * @param bytes_len The number of bytes in the array to convert. + * + * @return 0 on success, or -1 if the `hex_str` buffer is too small to store the resulting string. + */ +int atchops_bytes_to_hex(char *hex_str, const size_t hex_str_len, const unsigned char *bytes, const size_t bytes_len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packages/atchops/include/atchops/sha.h b/packages/atchops/include/atchops/sha.h index bf5fc947..038d3851 100644 --- a/packages/atchops/include/atchops/sha.h +++ b/packages/atchops/include/atchops/sha.h @@ -29,7 +29,7 @@ typedef enum atchops_md_type { * @param input the input to hash (in raw bytes) * @param input_len the length of the input buffer (most likely strlen(input)) * @param output (out) the output buffer to write the hash to. The length of this buffer should correspond to the hash - * type (e.g. 32 bytes for SHA256 (256 bits = 32 bytes)) + * type (e.g. 32 bytes for SHA256 (256 bits = 32 bytes) / 64 bytes for SHA512 (512 bits = 64 bytes)) * @return int 0 on success */ int atchops_sha_hash(const atchops_md_type md_type, const unsigned char *input, const size_t input_len, diff --git a/packages/atchops/include/atchops/utf8.h b/packages/atchops/include/atchops/utf8.h new file mode 100644 index 00000000..4bb5b2a7 --- /dev/null +++ b/packages/atchops/include/atchops/utf8.h @@ -0,0 +1,21 @@ +#ifndef ATCHOPS_UTF8_H +#define ATCHOPS_UTF8_H +#ifdef __cplusplus +extern "C" { +#endif +#include + +/** + * @brief UTF_8 encodes a string. Can be used to convert a unsgined char array into bytes + * + * @param input pointer to char buffer that is supposed to be encoded + * @param output double pointer to the output buffer that contains the bytes of the input string + * @param output_length pointer to the length of the output buffer + * @return + */ +int atchops_utf8_encode(const char *input, unsigned char **output, size_t *output_length); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/packages/atchops/src/aes.c b/packages/atchops/src/aes.c index 1e48065a..85f8eb41 100644 --- a/packages/atchops/src/aes.c +++ b/packages/atchops/src/aes.c @@ -45,8 +45,7 @@ int atchops_aes_generate_key(unsigned char *key, const enum atchops_aes_size key /* * 3. Seed the random number generator */ - if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (unsigned char *)personlization, strlen(personlization))) != - 0) { + if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (unsigned char *)personlization, strlen(personlization))) != 0) { goto exit; } diff --git a/packages/atchops/src/base64.c b/packages/atchops/src/base64.c index 637d24fc..b0b3dd6c 100644 --- a/packages/atchops/src/base64.c +++ b/packages/atchops/src/base64.c @@ -21,19 +21,19 @@ int atchops_base64_encode(const unsigned char *src, const size_t src_len, unsign } if (src_len <= 0) { - ret = 1; + ret = 2; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atchops_base64_encode: src_len is less than or equal to 0\n"); return ret; } if (dst == NULL) { - ret = 1; + ret = 3; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atchops_base64_encode: dst is NULL\n"); return ret; } if (dst_size <= 0) { - ret = 1; + ret = 4; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atchops_base64_encode: dst_size is less than or equal to 0\n"); return ret; } diff --git a/packages/atchops/src/hex.c b/packages/atchops/src/hex.c new file mode 100644 index 00000000..f6e0b8f2 --- /dev/null +++ b/packages/atchops/src/hex.c @@ -0,0 +1,42 @@ +#include "atchops/hex.h" + +#include +#include +#include +#include + +#define TAG "atchops-hex" + +int atchops_hex_to_bytes(unsigned char *bytes, const size_t byte_len, const char *hex_str) { + int ret = 0; + if (hex_str == NULL || bytes == NULL || byte_len <= 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "hex_string, bytes or byte_len is NULL\n"); + ret = -1; + return ret; + } + + for (size_t i = 0; i < byte_len; i++) { + if (sscanf(hex_str + (i * 2U), "%2hhx", &bytes[i]) != 1) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Error in hex_to_bytes conversion\n"); + ret = 1; + return ret; + } + } + + return ret; +} + +int atchops_bytes_to_hex(char *hex_str, const size_t hex_str_len, const unsigned char *bytes, const size_t bytes_len) { + // Ensure the hex string buffer is large enough: 2 chars for each byte + 1 for null terminator + if (hex_str_len < (bytes_len * 2 + 1)) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Insufficient space for hex string\n"); + return -1; + } + + for (size_t i = 0; i < bytes_len; i++) { + snprintf(hex_str + i * 2, hex_str_len - i * 2, "%02x", bytes[i]); + } + + hex_str[bytes_len * 2] = '\0'; + return 0; +} \ No newline at end of file diff --git a/packages/atchops/src/rsa_key.c b/packages/atchops/src/rsa_key.c index 0af30afa..f92ee636 100644 --- a/packages/atchops/src/rsa_key.c +++ b/packages/atchops/src/rsa_key.c @@ -363,7 +363,6 @@ int atchops_rsa_key_generate_base64(unsigned char **public_key_base64_output, /* * 8. Base64 encode the PKCS#8 formatted private key bytes to get the final private key in base64 format */ - // 8a. First, calculate the size of the base64 encoded private key and allocate memory const size_t private_key_base64_pkcs8_size = atchops_base64_encoded_size(private_key_non_base64_len); private_key_pkcs8_base64 = (char *)malloc(private_key_base64_pkcs8_size); diff --git a/packages/atchops/src/sha.c b/packages/atchops/src/sha.c index 75ac6668..5f9c45eb 100644 --- a/packages/atchops/src/sha.c +++ b/packages/atchops/src/sha.c @@ -13,7 +13,7 @@ int atchops_sha_hash(const atchops_md_type md_type, const unsigned char *input, * 1. Validate arguments */ - if (md_type != ATCHOPS_MD_SHA256) { + if (md_type != ATCHOPS_MD_SHA256 && md_type != ATCHOPS_MD_SHA512) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Unsupported md_type\n"); return ret; @@ -46,6 +46,7 @@ int atchops_sha_hash(const atchops_md_type md_type, const unsigned char *input, /* * 3. Prepare the hash context */ + // Setup the hash context based on the hash type if ((ret = mbedtls_md_setup(&md_ctx, mbedtls_md_info_from_type(atchops_mbedtls_md_map[md_type]), 0)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to setup the hash context\n"); goto exit; diff --git a/packages/atchops/src/utf8.c b/packages/atchops/src/utf8.c new file mode 100644 index 00000000..9f04c0ad --- /dev/null +++ b/packages/atchops/src/utf8.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include + +#define TAG "atchops-utf8" + +int atchops_utf8_encode(const char *input, unsigned char **output, size_t *output_length) { + int ret = 1; + + if (output_length == NULL || output == NULL || input == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "input, output or output_length is NULL\n"); + ret = -1; + return ret; + } + + // Get the length of the input string in wide characters + const size_t len_wchar = mbstowcs(NULL, input, 0); + if (len_wchar == (size_t)-1) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "invalid wide char length\n"); + ret = 1; + return ret; + } + + // Allocate memory for the wide character string + wchar_t *wstr = malloc((len_wchar + 1) * sizeof(wchar_t)); + if (wstr == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "unable to allocate memory for wstr\n"); + ret = 2; + return ret; + } + + // Convert to wide characters + mbstowcs(wstr, input, len_wchar + 1); + + // Calculate the size needed for UTF-8 encoding + *output_length = wcslen(wstr) * 4; // UTF-8 can use up to 4 bytes per character + *output = malloc(*output_length * sizeof(wchar_t)); + if (*output == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "unable to allocate memory for utf8_encode output\n"); + ret = 3; + goto exit; + } + + // Convert the wide character string to UTF-8 + *output_length = wcstombs((char *)*output, wstr, *output_length); + if (*output_length == (size_t)-1) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "invalid utf8 output string length\n"); + ret = 4; + free(*output); + goto exit; + } + + ret = 0; +exit: { + free(wstr); + return ret; +} +} diff --git a/packages/atclient/CMakeLists.txt b/packages/atclient/CMakeLists.txt index c9178a39..c625dd4a 100644 --- a/packages/atclient/CMakeLists.txt +++ b/packages/atclient/CMakeLists.txt @@ -102,6 +102,12 @@ if(NOT ESP_PLATFORM) include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/atchops.cmake) endif() + # Import atcommons + if(NOT TARGET atcommons) + set(atcommons_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../atcommons) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/atcommons.cmake) + endif () + # Create library targets add_library(${PROJECT_NAME} STATIC ${ATCLIENT_SOURCES}) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) diff --git a/packages/atclient/include/atclient/atclient.h b/packages/atclient/include/atclient/atclient.h index 5b3b4e9d..c34beabb 100644 --- a/packages/atclient/include/atclient/atclient.h +++ b/packages/atclient/include/atclient/atclient.h @@ -114,20 +114,31 @@ int atclient_start_atserver_connection(atclient *ctx, const char *secondaryhost, void atclient_stop_atserver_connection(atclient *ctx); /** - * @brief authenticate with secondary server with RSA pkam private key. it is expected atkeys has been populated with + * @brief authenticate with secondary server with RSA pkam private key. It is expected atkeys has been populated with * the pkam private key and atclient context is connected to the root server * * @param ctx initialized atclient context - * @param atserver_host host of secondary. if you do not know the host, you can use - * atclient_utils_find_atserver_address, this string is assumed to be null terminated - * @param atserver_port port of secondary. if you do not know the port, you can use - * atclient_utils_find_atserver_address, * @param atkeys populated atkeys, especially with the pkam private key * @param atsign the atsign the atkeys belong to, this string is assumed to be null terminated + * @param options pointer to an initialized atclient_authenticate_options struct that stored auth params * @return int 0 on success, non-zero on error */ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient_atkeys *atkeys, - atclient_pkam_authenticate_options *options); + atclient_authenticate_options *options); + +/** + * @brief authenticate with secondary server with AES CRAM key. This is supposed to be a one-time auth, to activate the + * atsign and set the necessary keys. Once the atsign is activated, use "atclient_pkam_authenticate()" + * + * @param ctx initialized atclient context + * @param atsign the atsign the atkeys belong to, this string is assumed to be null terminated + * @param cram_secret the AES key that will be used to authenticate. Expects a base64 encoded null terminated AES-256 + * key + * @param options pointer to an initialized atclient_authenticate_options struct that stored auth params + * @return int 0 on success, non-zero on error + */ +int atclient_cram_authenticate(atclient *ctx, const char *atsign, const char *cram_secret, + atclient_authenticate_options *options); /** * @brief Put a string value into a self key into your atServer. Putting a self key is a private value and is encrypted diff --git a/packages/atclient/include/atclient/atkey.h b/packages/atclient/include/atclient/atkey.h index 63b552d2..504dd0a5 100644 --- a/packages/atclient/include/atclient/atkey.h +++ b/packages/atclient/include/atclient/atkey.h @@ -32,6 +32,7 @@ typedef enum atclient_atkey_type { ATCLIENT_ATKEY_TYPE_PUBLIC_KEY, ATCLIENT_ATKEY_TYPE_SELF_KEY, ATCLIENT_ATKEY_TYPE_SHARED_KEY, + ATCLIENT_ATKEY_TYPE_RESERVED_KEY, } atclient_atkey_type; typedef struct atclient_atkey { @@ -272,6 +273,16 @@ int atclient_atkey_create_self_key(atclient_atkey *atkey, const char *name, cons int atclient_atkey_create_shared_key(atclient_atkey *atkey, const char *name, const char *shared_by, const char *shared_with, const char *namespace_str); +/** + * @brief Populates the atclient_key struct with the reserved key name provided. Reserved keys are usually restricted keys + * that are required the server for proper functioning and sometimes might not follow the standard atkey fomrmat + * + * @param atkey the atkey struct to populate, assumed that this was already initialized via atclient_atkey_init + * @param name name of your key, e.g. "privatekey:at_secret" + * @return int 0 on success, non-zero int on failure + */ +int atclient_atkey_create_reserved_key(atclient_atkey *atkey, const char *name); + #ifdef __cplusplus } #endif diff --git a/packages/atclient/include/atclient/atkeys_file.h b/packages/atclient/include/atclient/atkeys_file.h index 8feddb55..526e5448 100644 --- a/packages/atclient/include/atclient/atkeys_file.h +++ b/packages/atclient/include/atclient/atkeys_file.h @@ -3,7 +3,6 @@ #ifdef __cplusplus extern "C" { #endif - #include #include #include @@ -15,7 +14,6 @@ extern "C" { #define ATCLIENT_ATKEYS_FILE_AES_ENCRYPT_PUBLIC_KEY_STR_INDEX 0 #define ATCLIENT_ATKEYS_FILE_AES_ENCRYPT_PRIVATE_KEY_STR_INDEX 0 #define ATCLIENT_ATKEYS_FILE_SELF_ENCRYPTION_KEY_STR_INDEX 0 -#define ATCLIENT_ATKEYS_FILE_APKAM_SYMMETRIC_KEY_STR_INDEX 0 #define ATCLIENT_ATKEYS_FILE_ENROLLMENT_ID_STR_INDEX 0 #define ATCLIENT_ATKEYS_FILE_APKAM_SYMMETRIC_KEY_STR_INDEX 0 @@ -24,8 +22,8 @@ extern "C" { #define ATCLIENT_ATKEYS_FILE_AES_ENCRYPT_PUBLIC_KEY_STR_INITIALIZED (VALUE_INITIALIZED << 2) #define ATCLIENT_ATKEYS_FILE_AES_ENCRYPT_PRIVATE_KEY_STR_INITIALIZED (VALUE_INITIALIZED << 3) #define ATCLIENT_ATKEYS_FILE_SELF_ENCRYPTION_KEY_STR_INITIALIZED (VALUE_INITIALIZED << 4) -#define ATCLIENT_ATKEYS_FILE_APKAM_SYMMETRIC_KEY_STR_INITIALIZED (VALUE_INITIALIZED << 5) -#define ATCLIENT_ATKEYS_FILE_ENROLLMENT_ID_STR_INITIALIZED (VALUE_INITIALIZED << 6) +#define ATCLIENT_ATKEYS_FILE_ENROLLMENT_ID_STR_INITIALIZED (VALUE_INITIALIZED << 5) +#define ATCLIENT_ATKEYS_FILE_APKAM_SYMMETRIC_KEY_STR_INITIALIZED (VALUE_INITIALIZED << 6) #define ATCLIENT_ATKEYS_FILE_APKAM_PUBLIC_KEY_JSON_KEY "aesPkamPublicKey" #define ATCLIENT_ATKEYS_FILE_APKAM_PRIVATE_KEY_JSON_KEY "aesPkamPrivateKey" diff --git a/packages/atclient/include/atclient/constants.h b/packages/atclient/include/atclient/constants.h index 594b2289..ef6352f6 100755 --- a/packages/atclient/include/atclient/constants.h +++ b/packages/atclient/include/atclient/constants.h @@ -21,10 +21,13 @@ extern "C" { #define ATCLIENT_ERR_AT0015_KEY_NOT_FOUND -0x1980 // default param values for ATCLIENT PKAM AUTHENTICATE OPTIONS -#define ATCLIENT_PKAM_AUTHENTICATE_DEFAULT_AT_DIRECTORY_HOST "root.atsign.org" -#define ATCLIENT_PKAM_AUTHENTICATE_DEFAULT_AT_DIRECTORY_PORT 64 +#define ATCLIENT_DEFAULT_AT_DIRECTORY_HOST "root.atsign.org" +#define ATCLIENT_DEFAULT_AT_DIRECTORY_PORT 64 -#define DATA_TOKEN "data:" +#define ATCLIENT_DATA_TOKEN "data:" + +#define ATCLIENT_CRAM_PREFIX "cram" +#define ATCLIENT_CRAM_COMMAND_LEN 135 #define BLK "\e[0;30m" #define RED "\e[0;31m" diff --git a/packages/atclient/include/atclient/monitor.h b/packages/atclient/include/atclient/monitor.h index 8ca8f4ed..6c87e9c6 100644 --- a/packages/atclient/include/atclient/monitor.h +++ b/packages/atclient/include/atclient/monitor.h @@ -103,7 +103,7 @@ void atclient_monitor_free(atclient *monitor_conn); * @return int 0 on success */ int atclient_monitor_pkam_authenticate(atclient *monitor_conn, const char *atsign, const atclient_atkeys *atkeys, - atclient_pkam_authenticate_options *options); + atclient_authenticate_options *options); /** * @brief Set how long `atclient_monitor_read` should wait for a message before timing out diff --git a/packages/atclient/include/atclient/request_options.h b/packages/atclient/include/atclient/request_options.h index 10672f6d..2fbb15bc 100644 --- a/packages/atclient/include/atclient/request_options.h +++ b/packages/atclient/include/atclient/request_options.h @@ -39,14 +39,17 @@ extern "C" { #define ATCLIENT_GET_ATKEYS_REQUEST_OPTIONS_REGEX_INITIALIZED (VALUE_INITIALIZED << 0) #define ATCLIENT_GET_ATKEYS_REQUEST_OPTIONS_SHOW_HIDDEN_INITIALIZED (VALUE_INITIALIZED << 1) -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INDEX 0 -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INDEX 0 -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INDEX 0 -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INDEX 0 -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INITIALIZED (VALUE_INITIALIZED << 0) -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INITIALIZED (VALUE_INITIALIZED << 1) -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INITIALIZED (VALUE_INITIALIZED << 2) -#define ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INITIALIZED (VALUE_INITIALIZED << 3) +#define ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INDEX 0 +#define ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INDEX 0 +#define ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INDEX 0 +#define ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INDEX 0 +#define ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INITIALIZED (VALUE_INITIALIZED << 0) +#define ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INITIALIZED (VALUE_INITIALIZED << 1) +#define ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INITIALIZED (VALUE_INITIALIZED << 2) +#define ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INITIALIZED (VALUE_INITIALIZED << 3) + +#define ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INDEX 0 +#define ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INITIALIZED (VALUE_INITIALIZED << 0) /* * 1A. Put SelfKey @@ -106,8 +109,7 @@ typedef struct atclient_get_public_key_request_options { * 3. Delete */ typedef struct atclient_delete_request_options { - // empty - // future proofing + bool skip_shared_by_check; uint8_t _initialized_fields[1]; } atclient_delete_request_options; @@ -124,13 +126,13 @@ typedef struct atclient_get_atkeys_request_options { /* * 5. Pkam auhtenticate Request Options */ -typedef struct atclient_pkam_authenticate_options { +typedef struct atclient_authenticate_options { char *atdirectory_host; int atdirectory_port; char *atserver_host; int atserver_port; uint16_t _initialized_fields[1]; -} atclient_pkam_authenticate_options; +} atclient_authenticate_options; /* * 1A. Put SelfKey @@ -230,6 +232,11 @@ void atclient_get_public_key_request_options_unset_store_atkey_metadata( void atclient_delete_request_options_init(atclient_delete_request_options *options); void atclient_delete_request_options_free(atclient_delete_request_options *options); +bool atclient_delete_request_options_is_skip_shared_by_check_flag_initialized(atclient_delete_request_options *options); +void atclient_delete_request_options_set_skip_shared_by_check(atclient_delete_request_options *options, + const bool option); +void atclient_delete_request_options_unset_skip_shared_by_check(atclient_delete_request_options *options); + /* * 4. Get_AtKeys Request Options */ @@ -249,30 +256,24 @@ void atclient_get_atkeys_request_options_unset_show_hidden(atclient_get_atkeys_r /* * 5. AtClient_PKAM_Authenticate Options */ -void atclient_pkam_authenticate_options_init(atclient_pkam_authenticate_options *options); -void atclient_pkam_authenticate_options_free(atclient_pkam_authenticate_options *options); - -bool atclient_pkam_authenticate_options_is_atdirectory_host_initialized( - const atclient_pkam_authenticate_options *options); -int atclient_pkam_authenticate_options_set_at_directory_host(atclient_pkam_authenticate_options *options, - char *atdirectory_host); -void atclient_pkam_authenticate_options_unset_at_directory_host(atclient_pkam_authenticate_options *options); - -bool atclient_pkam_authenticate_options_is_atdirectory_port_initialized( - const atclient_pkam_authenticate_options *options); -int atclient_pkam_authenticate_options_set_at_directory_port(atclient_pkam_authenticate_options *options, - int atdirectory_port); -void atclient_pkam_authenticate_options_unset_at_directory_port(atclient_pkam_authenticate_options *options); - -bool atclient_pkam_authenticate_options_is_atserver_host_initialized(const atclient_pkam_authenticate_options *options); -int atclient_pkam_authenticate_options_set_atserver_host(atclient_pkam_authenticate_options *options, - char *atserver_host); -void atclient_pkam_authenticate_options_unset_atserver_host(atclient_pkam_authenticate_options *options); - -bool atclient_pkam_authenticate_options_is_atserver_port_initialized(const atclient_pkam_authenticate_options *options); -int atclient_pkam_authenticate_options_set_atserver_port(atclient_pkam_authenticate_options *options, - int atserver_port); -void atclient_pkam_authenticate_options_unset_atserver_port(atclient_pkam_authenticate_options *options); +void atclient_authenticate_options_init(atclient_authenticate_options *options); +void atclient_authenticate_options_free(atclient_authenticate_options *options); + +bool atclient_authenticate_options_is_atdirectory_host_initialized(const atclient_authenticate_options *options); +int atclient_authenticate_options_set_at_directory_host(atclient_authenticate_options *options, char *atdirectory_host); +void atclient_authenticate_options_unset_at_directory_host(atclient_authenticate_options *options); + +bool atclient_authenticate_options_is_atdirectory_port_initialized(const atclient_authenticate_options *options); +int atclient_authenticate_options_set_at_directory_port(atclient_authenticate_options *options, int atdirectory_port); +void atclient_authenticate_options_unset_at_directory_port(atclient_authenticate_options *options); + +bool atclient_authenticate_options_is_atserver_host_initialized(const atclient_authenticate_options *options); +int atclient_authenticate_options_set_atserver_host(atclient_authenticate_options *options, char *atserver_host); +void atclient_authenticate_options_unset_atserver_host(atclient_authenticate_options *options); + +bool atclient_authenticate_options_is_atserver_port_initialized(const atclient_authenticate_options *options); +int atclient_authenticate_options_set_atserver_port(atclient_authenticate_options *options, int atserver_port); +void atclient_authenticate_options_unset_atserver_port(atclient_authenticate_options *options); #ifdef __cplusplus } diff --git a/packages/atclient/src/atclient.c b/packages/atclient/src/atclient.c index c8dfb8b1..d879b81d 100755 --- a/packages/atclient/src/atclient.c +++ b/packages/atclient/src/atclient.c @@ -1,7 +1,8 @@ #include "atclient/atclient.h" #include "atchops/base64.h" +#include "atchops/hex.h" #include "atchops/rsa.h" -#include "atclient/atclient.h" + #include "atclient/atclient_utils.h" #include "atclient/atkeys.h" #include "atclient/connection.h" @@ -10,21 +11,23 @@ #include "atclient/request_options.h" #include "atclient/string_utils.h" #include "atlogger/atlogger.h" -#include +#include #include #include -#include #include #include -#define HOST_BUFFER_SIZE 1024 // the size of the buffer for the host name for root and secondary - +#define HOST_BUFFER_SIZE 1024 // the size of the buffer for the host name for root and secondary +#define CRAM_SECRET_LENGTH 128 // hex encoded string +#define SHA_512_DIGEST_SIZE 64 // standard SHA-512 digest len in bytes #define TAG "atclient" static void atclient_set_atsign_initialized(atclient *ctx, const bool initialized); static void atclient_set_atserver_connection_started(atclient *ctx, const bool started); static int atclient_pkam_authenticate_validate_arguments(const atclient *ctx, const atclient_atkeys *atkeys, const char *atsign); +static int atclient_cram_authenticate_validate_arguments(const atclient *ctx, const unsigned char *secret, + const char *atsign); void atclient_init(atclient *ctx) { /* @@ -101,7 +104,6 @@ int atclient_set_atsign(atclient *ctx, const char *atsign) { atclient_set_atsign_initialized(ctx, true); ret = 0; - goto exit; exit: { return ret; } } @@ -167,7 +169,7 @@ void atclient_stop_atserver_connection(atclient *ctx) { * 2. Stop the atserver connection */ if (atclient_is_atserver_connection_started(ctx)) { - atclient_connection_free(&(ctx->atserver_connection)); + atclient_connection_free(&ctx->atserver_connection); } memset(&(ctx->atserver_connection), 0, sizeof(atclient_connection)); atclient_set_atserver_connection_started(ctx, false); @@ -186,7 +188,7 @@ bool atclient_is_atsign_initialized(const atclient *ctx) { } int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient_atkeys *atkeys, - atclient_pkam_authenticate_options *options) { + atclient_authenticate_options *options) { int ret = 1; // error by default @@ -239,15 +241,15 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient goto exit; } - const char *atsign_without_at = (atsign_with_at + 1); + const char *atsign_without_at = atsign_with_at + 1; /* * 4. Get atserver_host and atserver_port */ bool should_free_atserver_host = false; if (options != NULL) { - if (atclient_pkam_authenticate_options_is_atdirectory_host_initialized(options) && - atclient_pkam_authenticate_options_is_atdirectory_port_initialized(options)) { + if (atclient_authenticate_options_is_atdirectory_host_initialized(options) && + atclient_authenticate_options_is_atdirectory_port_initialized(options)) { atserver_host = options->atdirectory_host; atserver_port = options->atdirectory_port; } @@ -295,7 +297,7 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient } char *str_with_data_prefix = NULL; - if (atclient_string_utils_get_substring_position((char *)recv, DATA_TOKEN, &str_with_data_prefix) != 0) { + if (atclient_string_utils_get_substring_position((char *)recv, ATCLIENT_DATA_TOKEN, &str_with_data_prefix) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); @@ -307,8 +309,8 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient * Let us sign the challenge with RSA-2048 PKAM Private Key and Base64 Encode it */ - challenge_len = strlen(str_with_data_prefix) - strlen(DATA_TOKEN); - memcpy(challenge, str_with_data_prefix + strlen(DATA_TOKEN), challenge_len); // +5 to skip the 'data:' prefix + challenge_len = strlen(str_with_data_prefix) - strlen(ATCLIENT_DATA_TOKEN); + memcpy(challenge, str_with_data_prefix + strlen(ATCLIENT_DATA_TOKEN), challenge_len); // +5 to skip the 'data:' prefix // sign if ((ret = atchops_rsa_sign(&atkeys->pkam_private_key, ATCHOPS_MD_SHA256, (unsigned char *)challenge, challenge_len, @@ -378,7 +380,6 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient ret = 0; - goto exit; exit: { free(atsign_with_at); free(root_cmd); @@ -391,6 +392,224 @@ exit: { } } +int atclient_cram_authenticate(atclient *ctx, const char *atsign, const char *cram_secret, + atclient_authenticate_options *options) { + int ret = 1; // error by default + + /* + * 1. Validate arguments + */ + if ((ret = atclient_cram_authenticate_validate_arguments(ctx, (unsigned char *)cram_secret, atsign)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_cram_authenticate_validate_arguments: %d\n", ret); + return ret; + } + + /* + * 2. Initialize variables and memory + */ + char *root_cmd = NULL; + char *from_cmd = NULL; + char *cram_cmd = NULL; + char *atsign_with_at = NULL; + char *atserver_host = NULL; + int atserver_port = 0; + + const size_t recvsize = 1024; // sufficient buffer size to receive 1. host & port from atDirectory, 2. challenge from + // `from:` noop_cmd, 3. cram success message from `cram:` noop_cmd + unsigned char recv[recvsize]; + memset(recv, 0, sizeof(unsigned char) * recvsize); + size_t recv_len; + + const size_t challenge_size = 256; // sufficient buffer size to hold the challenge received from `from:` noop_cmd + char challenge[challenge_size]; + memset(challenge, 0, sizeof(char) * challenge_size); + + const size_t digest_input_size = CRAM_SECRET_LENGTH + challenge_size; + unsigned char digest_input[digest_input_size]; + memset(digest_input, 0, digest_input_size); + size_t digest_input_len = 0; // actual length of data in digest_input + + unsigned char digest[SHA_512_DIGEST_SIZE]; + memset(digest, 0, sizeof(unsigned char) * SHA_512_DIGEST_SIZE); + + /* + * 3. Ensure that the atsign has the @ symbol. + */ + if ((ret = atclient_string_utils_atsign_with_at(atsign, &atsign_with_at)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_string_utils_atsign_with_at: %d\n", ret); + goto exit; + } + char *atsign_without_at = malloc(sizeof(char) * strlen(atsign_with_at) + 1); + if(atsign_without_at == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate memory for atsign_without_at"); + ret = -1; + goto exit; + } + strcpy(atsign_without_at, atsign_with_at + 1); + // Now we have two variables that we can use: `atsign_with_at` and `atsign_without_at` + + /* + * 4. Get atserver_host and atserver_port + */ + bool should_free_atserver_host = false; + if (options != NULL) { + if (atclient_authenticate_options_is_atdirectory_host_initialized(options) && + atclient_authenticate_options_is_atdirectory_port_initialized(options)) { + atserver_host = options->atdirectory_host; + atserver_port = options->atdirectory_port; + } + } + + if (atserver_host == NULL || atserver_port == 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Using production atDirectory to lookup atServer host and port\n"); + if ((ret = atclient_utils_find_atserver_address(ATCLIENT_ATDIRECTORY_PRODUCTION_HOST, + ATCLIENT_ATDIRECTORY_PRODUCTION_PORT, atsign, &atserver_host, + &atserver_port)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_utils_find_atserver_address: %d\n", ret); + goto exit; + } + // only free this memory if it was allocated internally (by atclient_utils_find_atserver_address) + should_free_atserver_host = true; + } + + /* + * 5. Start atServer connection (kill the existing connection if it exists) + */ + if ((ret = atclient_start_atserver_connection(ctx, atserver_host, atserver_port)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_start_atserver_connection: %d\n", ret); + goto exit; + } + + /* + * 6a. Build `from:` noop_cmd + */ + const size_t from_cmd_size = + strlen("from:") + strlen(atsign_without_at) + strlen("\r\n") + 1; // "from:" has a length of 5 + if ((from_cmd = malloc(sizeof(char) * from_cmd_size)) == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for from_cmd\n"); + goto exit; + } + snprintf(from_cmd, from_cmd_size, "from:%s\r\n", atsign_without_at); + + /* + * 6b. Send `from:` noop_cmd + */ + if ((ret = atclient_connection_send(&ctx->atserver_connection, (unsigned char *)from_cmd, from_cmd_size - 1, recv, + recvsize, &recv_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_connection_send: %d\n", ret); + goto exit; + } + char *str_with_data_prefix = NULL; + if (atclient_string_utils_get_substring_position((char *)recv, ATCLIENT_DATA_TOKEN, &str_with_data_prefix) != 0) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", + (int)recv_len, recv); + goto exit; + } + + /* + * 7. Move cram secret to digest_input + * CRAM digest-input will be of the form "CRAM secret + challenge from server" + */ + memcpy(digest_input, cram_secret, CRAM_SECRET_LENGTH); + digest_input_len = CRAM_SECRET_LENGTH; + + /* + * 8. We got `data:`, move this challenge into digest_input + * + */ + // trims 'data:' from the response and copy the challenge into 'digest_input' + memcpy(digest_input + digest_input_len, str_with_data_prefix + strlen(ATCLIENT_DATA_TOKEN), + recv_len - strlen(ATCLIENT_DATA_TOKEN)); + digest_input_len += strlen(str_with_data_prefix) - strlen(ATCLIENT_DATA_TOKEN); + + /* + * 9a. convert 'digest_input' to bytes using utf-8 encode + */ + unsigned char *digest_input_bytes = NULL; + size_t digest_input_bytes_len = 0; + if ((ret = atchops_utf8_encode((const char *)digest_input, &digest_input_bytes, &digest_input_bytes_len))) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atchops_utf8_encode: %d\n", ret); + ret = 1; + goto exit; + } + + /* + * 9b. generate SHA512 digest using the utf8-encoded bytes + */ + if ((ret = atchops_sha_hash(ATCHOPS_MD_SHA512, digest_input_bytes, digest_input_bytes_len, digest)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atchops_sha_hash: %d\n", ret); + goto exit; + } + /* + * 9b. hex encode the digest generated in the previous step + */ + const size_t digest_hex_encoded_len = SHA_512_DIGEST_SIZE * 2 + 1; // hex represents each byte with 2 characters + /0 + char *digest_hex_encoded = malloc(sizeof(char) * digest_hex_encoded_len); + if (digest_hex_encoded == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for digest_hex_encoded\n"); + goto exit; + } + + if ((ret = atchops_bytes_to_hex(digest_hex_encoded, digest_hex_encoded_len, digest, sizeof(digest))) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atchops_bytes_to_hex_string: %d\n", ret); + goto exit; + } + + /* + * 10a. Build `cram:` noop_cmd + */ + cram_cmd = malloc(sizeof(char) * ATCLIENT_CRAM_COMMAND_LEN + 1); // free later + if(cram_cmd == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate memory for cram_cmd"); + ret = -1; + goto exit; + } + ret = snprintf(cram_cmd, ATCLIENT_CRAM_COMMAND_LEN + 1, "%s:%s\r\n", ATCLIENT_CRAM_PREFIX, digest_hex_encoded); + /* + * 10b. Send `cram:` noop_cmd + */ + memset(recv, 0, sizeof(unsigned char) * recvsize); + if ((ret = atclient_connection_send(&ctx->atserver_connection, (unsigned char *)cram_cmd, ATCLIENT_CRAM_COMMAND_LEN, + recv, recvsize, &recv_len)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_connection_send: %d\n", ret); + goto exit; + } + /* + * 10c. check for data:success + */ + if (!atclient_string_utils_starts_with((char *)recv, "data:success")) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:success\"\n", + (int)recv_len, recv); + goto exit; + } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "CRAM auth successful\n"); + + /* + * 11. Set up the atclient context + */ + + // initialize ctx->atsign.atsign and ctx->atsign.withour_prefix_str to the newly authenticated atSign + if ((ret = atclient_set_atsign(ctx, atsign_with_at)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_set_atsign: %d\n", ret); + goto exit; + } + + ret = 0; + +exit: { + free(atsign_without_at); + free(root_cmd); + free(from_cmd); + free(cram_cmd); + if (should_free_atserver_host) { + free(atserver_host); + } + return ret; +} +} + int atclient_send_heartbeat(atclient *heartbeat_conn) { int ret = -1; @@ -434,7 +653,6 @@ int atclient_send_heartbeat(atclient *heartbeat_conn) { memset(recv, 0, sizeof(unsigned char) * recvsize); } size_t recv_len = 0; - char *ptr = (char *)recv; if ((ret = atclient_connection_send(&heartbeat_conn->atserver_connection, (unsigned char *)noop_cmd, noop_cmd_len, recv, recvsize, &recv_len)) != 0) { @@ -450,15 +668,13 @@ int atclient_send_heartbeat(atclient *heartbeat_conn) { /* * 3. Parse response */ - // how about just doing ptr == "data:ok" ? - if (strcmp(ptr, "data:ok") != 0) { + if (strcmp((const char *)recv, "data:ok") != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to receive heartbeat response\n"); ret = -1; goto exit; } ret = 0; - goto exit; exit: { if (!heartbeat_conn->async_read) { free(recv); @@ -469,8 +685,8 @@ exit: { bool atclient_is_connected(atclient *ctx) { return atclient_connection_is_connected(&(ctx->atserver_connection)); } -void atclient_set_read_timeout(atclient *ctx, int timeout_ms) { - mbedtls_ssl_conf_read_timeout(&(ctx->atserver_connection.ssl_config), timeout_ms); +void atclient_set_read_timeout(atclient *ctx, const int timeout_ms) { + mbedtls_ssl_conf_read_timeout(&ctx->atserver_connection.ssl_config, timeout_ms); } static void atclient_set_atsign_initialized(atclient *ctx, const bool initialized) { @@ -497,11 +713,39 @@ static int atclient_pkam_authenticate_validate_arguments(const atclient *ctx, co goto exit; } - if (atsign == NULL || strlen(atsign) == 0) { + if (NULL == atsign || strlen(atsign) == 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atsign is NULL or the length is 0\n"); goto exit; } + if (atkeys == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkeys is NULL\n"); + goto exit; + } + ret = 0; exit: { return ret; } } + +static int atclient_cram_authenticate_validate_arguments(const atclient *ctx, const unsigned char *secret, + const char *atsign) { + int ret = 1; + if (ctx == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "ctx is NULL\n"); + goto exit; + } + + if (atsign == NULL || strlen(atsign) == 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atsign is NULL or the length is 0"); + goto exit; + } + + if (secret == NULL || strlen((const char *)secret) < CRAM_SECRET_LENGTH) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Invalid CRAM secret length"); + goto exit; + } + + ret = 0; + +exit: { return ret; } +} diff --git a/packages/atclient/src/atclient_delete.c b/packages/atclient/src/atclient_delete.c index b37f00ed..d2c11d82 100755 --- a/packages/atclient/src/atclient_delete.c +++ b/packages/atclient/src/atclient_delete.c @@ -3,21 +3,22 @@ #include "atclient/constants.h" #include "atclient/string_utils.h" #include "atlogger/atlogger.h" -#include #include +#include #include #define TAG "atclient_delete" -static int atclient_delete_validate_arguments(const atclient *atclient, const atclient_atkey *atkey); +static int atclient_delete_validate_arguments(const atclient *atclient, const atclient_atkey *atkey, + atclient_delete_request_options *options); -int atclient_delete(atclient *atclient, const atclient_atkey *atkey, const atclient_delete_request_options *options, int *commit_id) { +int atclient_delete(atclient *atclient, const atclient_atkey *atkey, const atclient_delete_request_options *options, + int *commit_id) { int ret = 1; - /* * 1. Check arguments */ - if ((ret = atclient_delete_validate_arguments(atclient, atkey)) != 0) { + if ((ret = atclient_delete_validate_arguments(atclient, atkey, (atclient_delete_request_options*)options)) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_delete_validate_arguments: %d\n", ret); return ret; @@ -64,8 +65,8 @@ int atclient_delete(atclient *atclient, const atclient_atkey *atkey, const atcli /* * 4. Send command */ - if ((ret = atclient_connection_send(&(atclient->atserver_connection), (unsigned char *)delete_cmd, delete_cmd_size - 1, - recv, recv_size, &recv_len)) != 0) { + if ((ret = atclient_connection_send(&atclient->atserver_connection, (unsigned char *)delete_cmd, + delete_cmd_size - 1, recv, recv_size, &recv_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_connection_send: %d\n", ret); goto exit; } @@ -74,23 +75,22 @@ int atclient_delete(atclient *atclient, const atclient_atkey *atkey, const atcli goto exit; } - char *response = (char *)recv; + const char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if (atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); - if(commit_id != NULL) { + if (commit_id != NULL) { *commit_id = atoi(response_trimmed); } ret = 0; - goto exit; exit: { free(recv); free(atkey_str); @@ -99,7 +99,8 @@ exit: { } } -static int atclient_delete_validate_arguments(const atclient *atclient, const atclient_atkey *atkey) { +static int atclient_delete_validate_arguments(const atclient *atclient, const atclient_atkey *atkey, + atclient_delete_request_options *options) { int ret = 1; if (atclient == NULL) { @@ -132,6 +133,12 @@ static int atclient_delete_validate_arguments(const atclient *atclient, const at goto exit; } + // skip atclient_atkey_is_shared_by_initialized() if atclient_delete_request_options->skip_shared_by_check is true + if(atclient_delete_request_options_is_skip_shared_by_check_flag_initialized(options) && options->skip_shared_by_check) { + ret = 0; + goto exit; + } + if (!atclient_atkey_is_shared_by_initialized(atkey)) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_atkey_is_shared_by_initialized is false\n"); @@ -139,6 +146,5 @@ static int atclient_delete_validate_arguments(const atclient *atclient, const at } ret = 0; - goto exit; exit: { return ret; } } \ No newline at end of file diff --git a/packages/atclient/src/atclient_get_atkeys.c b/packages/atclient/src/atclient_get_atkeys.c index 17affa4e..3a2604d0 100755 --- a/packages/atclient/src/atclient_get_atkeys.c +++ b/packages/atclient/src/atclient_get_atkeys.c @@ -88,13 +88,13 @@ int atclient_get_atkeys(atclient *atclient, atclient_atkey **atkey, size_t *outp char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); root = cJSON_Parse(response_trimmed); if (root == NULL) { diff --git a/packages/atclient/src/atclient_get_public_key.c b/packages/atclient/src/atclient_get_public_key.c index 9040342d..4af9ccc4 100755 --- a/packages/atclient/src/atclient_get_public_key.c +++ b/packages/atclient/src/atclient_get_public_key.c @@ -83,13 +83,13 @@ int atclient_get_public_key(atclient *atclient, atclient_atkey *atkey, char **va char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); if ((root = cJSON_Parse(response_trimmed)) == NULL) { ret = 1; diff --git a/packages/atclient/src/atclient_get_self_key.c b/packages/atclient/src/atclient_get_self_key.c index 81fe66e5..09408d8e 100755 --- a/packages/atclient/src/atclient_get_self_key.c +++ b/packages/atclient/src/atclient_get_self_key.c @@ -91,13 +91,13 @@ int atclient_get_self_key(atclient *atclient, atclient_atkey *atkey, char **valu char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); if ((root = cJSON_Parse(response_trimmed)) == NULL) { ret = 1; diff --git a/packages/atclient/src/atclient_get_shared_key.c b/packages/atclient/src/atclient_get_shared_key.c index dc64031a..667f3438 100755 --- a/packages/atclient/src/atclient_get_shared_key.c +++ b/packages/atclient/src/atclient_get_shared_key.c @@ -229,13 +229,13 @@ static int atclient_get_shared_key_shared_by_me_with_other( char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); if ((root = cJSON_Parse(response_trimmed)) == NULL) { ret = 1; @@ -455,13 +455,13 @@ atclient_get_shared_key_shared_by_other_with_me(atclient *atclient, atclient_atk char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); if ((root = cJSON_Parse(response_trimmed)) == NULL) { ret = 1; diff --git a/packages/atclient/src/atclient_put_public_key.c b/packages/atclient/src/atclient_put_public_key.c index dd5d23b1..b246d05d 100755 --- a/packages/atclient/src/atclient_put_public_key.c +++ b/packages/atclient/src/atclient_put_public_key.c @@ -1,6 +1,4 @@ #include -#include -#include #include #include #include @@ -88,13 +86,13 @@ int atclient_put_public_key(atclient *ctx, atclient_atkey *atkey, const char *va char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); /* * 5. Receive commit id diff --git a/packages/atclient/src/atclient_put_self_key.c b/packages/atclient/src/atclient_put_self_key.c index f95afae3..3ad09345 100755 --- a/packages/atclient/src/atclient_put_self_key.c +++ b/packages/atclient/src/atclient_put_self_key.c @@ -161,13 +161,13 @@ int atclient_put_self_key(atclient *ctx, atclient_atkey *atkey, const char *valu char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); /* * 5. Receive commit id diff --git a/packages/atclient/src/atclient_put_shared_key.c b/packages/atclient/src/atclient_put_shared_key.c index 64627bf7..7819309d 100755 --- a/packages/atclient/src/atclient_put_shared_key.c +++ b/packages/atclient/src/atclient_put_shared_key.c @@ -173,13 +173,13 @@ int atclient_put_shared_key(atclient *ctx, atclient_atkey *atkey, const char *va char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); /* * 8. Return commit id */ diff --git a/packages/atclient/src/atkey.c b/packages/atclient/src/atkey.c index 1ded468d..36bea17f 100644 --- a/packages/atclient/src/atkey.c +++ b/packages/atclient/src/atkey.c @@ -73,19 +73,22 @@ size_t atclient_atkey_strlen(const atclient_atkey *atkey) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey is NULL\n"); return 0; } - if (!atclient_atkey_is_key_initialized(atkey) || !atclient_atkey_is_shared_by_initialized(atkey)) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey->key or atkey->shared_by is not initialized\n"); + if (!atclient_atkey_is_key_initialized(atkey) || strlen(atkey->key) <= 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey->key is not initialized\n"); return 0; } - if (strlen(atkey->key) <= 0 || strlen(atkey->shared_by) <= 0) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey->key or atkey->shared_by is empty\n"); + + atclient_atkey_type type = atclient_atkey_get_type(atkey); + + if((!atclient_atkey_is_shared_by_initialized(atkey) || strlen(atkey->shared_by) <= 0) && type != ATCLIENT_ATKEY_TYPE_RESERVED_KEY){ + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey->shared_by is not initialized\n"); return 0; } - atclient_atkey_type type = atclient_atkey_get_type(atkey); if (type == ATCLIENT_ATKEY_TYPE_UNKNOWN) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey type is unknown\n"); return 0; } + size_t len = 0; if (atclient_atkey_metadata_is_is_cached_initialized(&(atkey->metadata)) && atkey->metadata.is_cached) { len += strlen("cached:"); @@ -100,7 +103,9 @@ size_t atclient_atkey_strlen(const atclient_atkey *atkey) { if (atclient_atkey_is_namespacestr_initialized(atkey) && strlen(atkey->namespace_str) > 0) { len += strlen(".") + strlen(atkey->namespace_str); } - len += strlen(atkey->shared_by); + if(atclient_atkey_is_shared_by_initialized(atkey)){ + len += strlen(atkey->shared_by); + } return len; } @@ -315,7 +320,9 @@ int atclient_atkey_to_string(const atclient_atkey *atkey, char **atkeystr) { return ret; } - if (!atclient_atkey_is_shared_by_initialized(atkey) || strlen(atkey->shared_by) <= 0) { + // ensure all key types have shared_by set. Except, reserved keys can sometimes not have shared by + if (atkey_type != ATCLIENT_ATKEY_TYPE_RESERVED_KEY && + (!atclient_atkey_is_shared_by_initialized(atkey) || strlen(atkey->shared_by)) <= 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey->shared_by is not initialized or strlen(atkey->shared_by) <= 0. AtKey is incomplete.\n"); return ret; @@ -367,8 +374,10 @@ int atclient_atkey_to_string(const atclient_atkey *atkey, char **atkeystr) { index_pos += strlen(".") + strlen(atkey->namespace_str); } - snprintf(*atkeystr + index_pos, atkey_str_size - index_pos, "%s", atkey->shared_by); - index_pos += strlen(atkey->shared_by); + if (atclient_atkey_is_shared_by_initialized(atkey)) { + snprintf(*atkeystr + index_pos, atkey_str_size - index_pos, "%s", atkey->shared_by); + index_pos += strlen(atkey->shared_by); + } if (index_pos != atkey_str_size - 1) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_WARN, @@ -552,7 +561,7 @@ void atclient_atkey_unset_shared_with(atclient_atkey *atkey) { atclient_atkey_type atclient_atkey_get_type(const atclient_atkey *atkey) { if (atclient_atkey_metadata_is_is_public_initialized(&(atkey->metadata)) && atkey->metadata.is_public && - !atclient_atkey_is_shared_with_initialized(atkey)) { + !atclient_atkey_is_shared_with_initialized(atkey) && atclient_atkey_is_shared_by_initialized(atkey)) { return ATCLIENT_ATKEY_TYPE_PUBLIC_KEY; } if (atclient_atkey_is_shared_by_initialized(atkey) && atclient_atkey_is_shared_with_initialized(atkey)) { @@ -565,6 +574,9 @@ atclient_atkey_type atclient_atkey_get_type(const atclient_atkey *atkey) { if (atclient_atkey_is_shared_by_initialized(atkey) && !atclient_atkey_is_shared_with_initialized(atkey)) { return ATCLIENT_ATKEY_TYPE_SELF_KEY; } + if (!atclient_atkey_is_shared_by_initialized(atkey) && !atclient_atkey_is_shared_with_initialized(atkey)) { + return ATCLIENT_ATKEY_TYPE_RESERVED_KEY; + } return ATCLIENT_ATKEY_TYPE_UNKNOWN; } @@ -750,3 +762,34 @@ int atclient_atkey_create_shared_key(atclient_atkey *atkey, const char *key, con goto exit; exit: { return ret; } } + +int atclient_atkey_create_reserved_key(atclient_atkey *atkey, const char *key) { + int ret = 1; + + if (atkey == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atkey is NULL. This is a required argument.\n"); + goto exit; + } + + if (key == NULL) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "key is NULL. This is a required argument.\n"); + goto exit; + } + + if (strlen(key) <= 0) { + ret = 1; + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "key is empty. This is a required argument.\n"); + goto exit; + } + + if ((ret = atclient_atkey_set_key(atkey, key)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_atkey_set_key failed\n"); + goto exit; + } + + ret = 0; + goto exit; +exit: { return ret; } +} diff --git a/packages/atclient/src/atkeys.c b/packages/atclient/src/atkeys.c index 27009141..5add317d 100644 --- a/packages/atclient/src/atkeys.c +++ b/packages/atclient/src/atkeys.c @@ -1,5 +1,4 @@ #include "atclient/atkeys.h" -#include "atclient/atkeys_file.h" #include "atlogger/atlogger.h" #include #include @@ -284,7 +283,7 @@ int atclient_atkeys_set_apkam_symmetric_key_base64(atclient_atkeys *atkeys, cons return ret; } - if(atclient_atkeys_is_apkam_symmetric_key_base64_initialized(atkeys)) { + if (atclient_atkeys_is_apkam_symmetric_key_base64_initialized(atkeys)) { unset_apkam_symmetric_key_base64(atkeys); } @@ -779,7 +778,7 @@ int atclient_atkeys_populate_from_strings(atclient_atkeys *atkeys, const char *a /* * 6. enrollment id, if it exists - */ + */ if (enrollment_id_str != NULL && enrollment_id_str_len > 0) { if ((ret = atclient_atkeys_set_enrollment_id(atkeys, enrollment_id_str, enrollment_id_str_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_atkeys_set_enrollment_id: %d\n", ret); @@ -808,7 +807,8 @@ int atclient_atkeys_populate_from_atkeys_file(atclient_atkeys *atkeys, const atc goto exit; } - if (atclient_atkeys_file_is_enrollment_id_str_initialized(atkeys_file) && atclient_atkeys_file_is_apkam_symmetric_key_str_initialized(atkeys_file)) { + if (atclient_atkeys_file_is_enrollment_id_str_initialized(atkeys_file) && + atclient_atkeys_file_is_apkam_symmetric_key_str_initialized(atkeys_file)) { if ((ret = atclient_atkeys_populate_from_strings( atkeys, atkeys_file->aes_pkam_public_key_str, strlen(atkeys_file->aes_pkam_public_key_str), atkeys_file->aes_pkam_private_key_str, strlen(atkeys_file->aes_pkam_private_key_str), @@ -958,7 +958,7 @@ int atclient_atkeys_write_to_atkeys_file(atclient_atkeys *atkeys, atclient_atkey unsigned char rsa_key_encrypted[rsa_key_encrypted_size]; size_t rsa_key_encrypted_len = 0; - const size_t rsa_key_encrypted_base64_size = atchops_base64_encoded_size(rsa_key_encrypted_size); + const size_t rsa_key_encrypted_base64_size = atchops_base64_encoded_size(rsa_key_encrypted_size); unsigned char rsa_key_encrypted_base64[rsa_key_encrypted_base64_size]; size_t rsa_key_encrypted_base64_len = 0; @@ -987,7 +987,8 @@ int atclient_atkeys_write_to_atkeys_file(atclient_atkeys *atkeys, atclient_atkey goto exit; } - if((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { + if ((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, + rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "base64 encode pkam public key: %d\n", ret); goto exit; } @@ -1009,7 +1010,8 @@ int atclient_atkeys_write_to_atkeys_file(atclient_atkeys *atkeys, atclient_atkey goto exit; } - if((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { + if ((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, + rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "base64 encode pkam private key: %d\n", ret); goto exit; } @@ -1031,7 +1033,8 @@ int atclient_atkeys_write_to_atkeys_file(atclient_atkeys *atkeys, atclient_atkey goto exit; } - if((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { + if ((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, + rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "base64 encode encrypt public key: %d\n", ret); goto exit; } @@ -1053,7 +1056,8 @@ int atclient_atkeys_write_to_atkeys_file(atclient_atkeys *atkeys, atclient_atkey goto exit; } - if((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { + if ((ret = atchops_base64_encode(rsa_key_encrypted, rsa_key_encrypted_len, rsa_key_encrypted_base64, + rsa_key_encrypted_base64_size, &rsa_key_encrypted_base64_len)) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "base64 encode encrypt private key: %d\n", ret); goto exit; } @@ -1065,14 +1069,16 @@ int atclient_atkeys_write_to_atkeys_file(atclient_atkeys *atkeys, atclient_atkey } // 4e. self encryption key - if ((ret = atclient_atkeys_file_set_self_encryption_key_str(atkeys_file, atkeys->self_encryption_key_base64, strlen(atkeys->self_encryption_key_base64))) != 0) { + if ((ret = atclient_atkeys_file_set_self_encryption_key_str(atkeys_file, atkeys->self_encryption_key_base64, + strlen(atkeys->self_encryption_key_base64))) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "set self encryption key str: %d\n", ret); goto exit; } // 4f. apkam symmetric key (optional) if (atclient_atkeys_is_apkam_symmetric_key_base64_initialized(atkeys)) { - if ((ret = atclient_atkeys_file_set_apkam_symmetric_key_str(atkeys_file, atkeys->apkam_symmetric_key_base64, strlen(atkeys->apkam_symmetric_key_base64))) != 0) { + if ((ret = atclient_atkeys_file_set_apkam_symmetric_key_str(atkeys_file, atkeys->apkam_symmetric_key_base64, + strlen(atkeys->apkam_symmetric_key_base64))) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "set apkam symmetric key str: %d\n", ret); goto exit; } @@ -1080,7 +1086,8 @@ int atclient_atkeys_write_to_atkeys_file(atclient_atkeys *atkeys, atclient_atkey // 4h. enrollment id (optional) if (atclient_atkeys_is_enrollment_id_initialized(atkeys)) { - if ((ret = atclient_atkeys_file_set_enrollment_id_str(atkeys_file, atkeys->enrollment_id, strlen(atkeys->enrollment_id))) != 0) { + if ((ret = atclient_atkeys_file_set_enrollment_id_str(atkeys_file, atkeys->enrollment_id, + strlen(atkeys->enrollment_id))) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "set enrollment id str: %d\n", ret); goto exit; } diff --git a/packages/atclient/src/atkeys_file.c b/packages/atclient/src/atkeys_file.c index 5ef7426c..1b428429 100644 --- a/packages/atclient/src/atkeys_file.c +++ b/packages/atclient/src/atkeys_file.c @@ -147,7 +147,7 @@ int atclient_atkeys_file_from_string(atclient_atkeys_file *atkeys_file, const ch cJSON *apkam_symmetric_key = cJSON_GetObjectItem(root, ATCLIENT_ATKEYS_FILE_APKAM_SYMMETRIC_KEY_JSON_KEY); if (apkam_symmetric_key != NULL) { if ((ret = set_apkam_symmetric_key_str(atkeys_file, apkam_symmetric_key->valuestring, - strlen(apkam_symmetric_key->valuestring))) != 0) { + strlen(apkam_symmetric_key->valuestring))) != 0) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "set_apkam_symmetric_key_str: %d\n", ret); goto exit; } @@ -215,7 +215,7 @@ int atclient_atkeys_file_write_to_path(atclient_atkeys_file *atkeys_file, const * 2. Variables */ - cJSON *root = NULL; // free later + cJSON *root = NULL; // free later char *json_str = NULL; // free later root = cJSON_CreateObject(); @@ -244,7 +244,7 @@ int atclient_atkeys_file_write_to_path(atclient_atkeys_file *atkeys_file, const cJSON_AddStringToObject(root, "selfEncryptionKey", atkeys_file->self_encryption_key_str); } - if(is_apkam_symmetric_key_str_initialized(atkeys_file)) { + if (is_apkam_symmetric_key_str_initialized(atkeys_file)) { cJSON_AddStringToObject(root, "apkamSymmetricKey", atkeys_file->apkam_symmetric_key_str); } @@ -273,10 +273,10 @@ int atclient_atkeys_file_write_to_path(atclient_atkeys_file *atkeys_file, const ret = 0; exit: { - if(json_str != NULL) { + if (json_str != NULL) { free(json_str); } - if(root != NULL) { + if (root != NULL) { cJSON_Delete(root); } return ret; diff --git a/packages/atclient/src/connection.c b/packages/atclient/src/connection.c index 35ff7cb6..922d4c3e 100644 --- a/packages/atclient/src/connection.c +++ b/packages/atclient/src/connection.c @@ -4,6 +4,7 @@ #include "atclient/connection_hooks.h" #include "atclient/constants.h" #include "atlogger/atlogger.h" +#include #include #include #include @@ -170,6 +171,7 @@ int atclient_connection_connect(atclient_connection *ctx, const char *host, cons atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "mbedtls_ssl_get_verify_result failed with exit code: %d\n", ret); goto exit; } + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO, "Connected\n"); // =============== // after connect @@ -222,7 +224,6 @@ int atclient_connection_connect(atclient_connection *ctx, const char *host, cons } ret = 0; - goto exit; exit: { if (ret != 0) { @@ -337,13 +338,13 @@ int atclient_connection_write(atclient_connection *ctx, const unsigned char *val } ret = 0; - goto exit; exit: { return ret; } } int atclient_connection_send(atclient_connection *ctx, const unsigned char *src, const size_t src_len, unsigned char *recv, const size_t recv_size, size_t *recv_len) { int ret = 1; + char error_buf[100]; /* * 1. Validate arguments @@ -402,8 +403,12 @@ int atclient_connection_send(atclient_connection *ctx, const unsigned char *src, // if return value is positive and less than src_len // we should continue to write from the appropriate offset // (multiple writes must be summed to determine total data written) - if ((ret = mbedtls_ssl_write(&(ctx->ssl), src, src_len)) <= 0) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "mbedtls_ssl_write failed with exit code: %d\n", ret); + if (src[src_len - 1] != '\n') { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_WARN, "command does not have a trailing \\n character:\t%s\n", src); + } + if ((ret = mbedtls_ssl_write(&ctx->ssl, src, src_len)) <= 0) { // error only when the returned value is negative + mbedtls_strerror(ret, error_buf, sizeof(error_buf)); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "mbedtls_ssl_write returned -0x%x: %s\n", -ret, error_buf); goto exit; } @@ -449,6 +454,7 @@ int atclient_connection_send(atclient_connection *ctx, const unsigned char *src, * 7. Exit if recv is NULL */ if (recv == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv is null. exiting\n"); ret = 0; goto exit; } @@ -484,8 +490,9 @@ int atclient_connection_send(atclient_connection *ctx, const unsigned char *src, do { // TODO: better read handling // - see the improved implementation in atclient_monitor_read - if ((ret = mbedtls_ssl_read(&(ctx->ssl), recv + l, recv_size - l)) <= 0) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "mbedtls_ssl_read failed with exit code: %d\n", ret); + if ((ret = mbedtls_ssl_read(&ctx->ssl, recv + l, recv_size - l)) <= 0) { + mbedtls_strerror(ret, error_buf, sizeof(error_buf)); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "mbedtls_ssl_read returned err: -0x%x: %s\n", -ret, error_buf); goto exit; } l = l + ret; @@ -528,7 +535,7 @@ int atclient_connection_send(atclient_connection *ctx, const unsigned char *src, */ if (atlogger_get_logging_level() >= ATLOGGER_LOGGING_LEVEL_DEBUG) { unsigned char *recvcopy = NULL; - if ((recvcopy = malloc(sizeof(unsigned char) * (*recv_len))) != NULL) { + if ((recvcopy = malloc(sizeof(unsigned char) * *recv_len)) != NULL) { memcpy(recvcopy, recv, *recv_len); atlogger_fix_stdout_buffer((char *)recvcopy, *recv_len); atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_DEBUG, "\t%sRECV: %s\"%.*s\"%s\n", BMAG, HMAG, *recv_len, recvcopy, @@ -568,7 +575,6 @@ int atclient_connection_disconnect(atclient_connection *ctx) { atclient_connection_disable_connection(ctx); ret = 0; - goto exit; exit: { return ret; } } diff --git a/packages/atclient/src/encryption_key_helpers.c b/packages/atclient/src/encryption_key_helpers.c index 3c324025..9fdcaede 100644 --- a/packages/atclient/src/encryption_key_helpers.c +++ b/packages/atclient/src/encryption_key_helpers.c @@ -83,13 +83,13 @@ int atclient_get_public_encryption_key(atclient *ctx, const char *atsign, char * char *response = (char *)recv; char *response_trimmed = NULL; // below method points the response_trimmed variable to the position of 'data:' substring - if(atclient_string_utils_get_substring_position(response, DATA_TOKEN, &response_trimmed) != 0) { + if(atclient_string_utils_get_substring_position(response, ATCLIENT_DATA_TOKEN, &response_trimmed) != 0) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "recv was \"%.*s\" and did not have prefix \"data:\"\n", (int)recv_len, recv); goto exit; } - response_trimmed = response_trimmed + strlen(DATA_TOKEN); + response_trimmed = response_trimmed + strlen(ATCLIENT_DATA_TOKEN); /* * 6. Allocate memory for public_encryption_key and give output to caller diff --git a/packages/atclient/src/monitor.c b/packages/atclient/src/monitor.c index 77ab4bfb..478c2e9d 100644 --- a/packages/atclient/src/monitor.c +++ b/packages/atclient/src/monitor.c @@ -39,7 +39,7 @@ void atclient_monitor_init(atclient *monitor_conn) { atclient_init(monitor_conn) void atclient_monitor_free(atclient *monitor_conn) { atclient_free(monitor_conn); } int atclient_monitor_pkam_authenticate(atclient *monitor_conn, const char *atsign, const atclient_atkeys *atkeys, - atclient_pkam_authenticate_options *options) { + atclient_authenticate_options *options) { int ret = 1; if ((ret = atclient_pkam_authenticate(monitor_conn, atsign, atkeys, options)) != 0) { diff --git a/packages/atclient/src/request_options.c b/packages/atclient/src/request_options.c index d52e728c..7d8e9880 100644 --- a/packages/atclient/src/request_options.c +++ b/packages/atclient/src/request_options.c @@ -10,8 +10,8 @@ #define TAG "request_options" // default param values for ATCLIENT PKAM AUTHENTICATE OPTIONS -#define ATCLIENT_PKAM_AUTHENTICATE_DEFAULT_ROOT_SERVER_HOST "root.atsign.org" -#define ATCLIENT_PKAM_AUTHENTICATE_DEFAULT_ROOT_SERVER_PORT 64 +#define ATCLIENT_AUTHENTICATE_DEFAULT_ROOT_SERVER_HOST "root.atsign.org" +#define ATCLIENT_AUTHENTICATE_DEFAULT_ROOT_SERVER_PORT 64 static void atclient_put_shared_key_request_options_set_shared_encryption_key_initialized( atclient_put_shared_key_request_options *options, const bool initialized); @@ -38,7 +38,9 @@ static void atclient_get_atkeys_request_options_set_regex_initialized(atclient_g static void atclient_get_atkeys_request_options_set_show_hidden_initialized(atclient_get_atkeys_request_options *options, const bool initialized); - +static void +atclient_delete_request_options_skip_shared_by_check_set_intitialized(atclient_delete_request_options *options, + const bool initialized); /* * ================= * 1A. Put SelfKey @@ -1200,6 +1202,118 @@ void atclient_get_public_key_request_options_unset_store_atkey_metadata( atclient_get_public_key_request_options_set_store_atkey_metadata_initialized(options, false); } +void atclient_delete_request_options_init(atclient_delete_request_options *options) { + /* + * 1. Validate arguments + */ + if (options == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_delete_request_options_init: Invalid arguments\n"); + return; + } + + /* + * 2. Initialize the options + */ + memset(options, 0, sizeof(atclient_delete_request_options)); +} + +void atclient_delete_request_options_free(atclient_delete_request_options *options) { + /* + * 1. Validate arguments + */ + if (options == NULL) { + return; + } + + /* + * 2. Reset the value + */ + if (atclient_delete_request_options_is_skip_shared_by_check_flag_initialized(options)) { + atclient_delete_request_options_unset_skip_shared_by_check(options); + } +} + +bool atclient_delete_request_options_is_skip_shared_by_check_flag_initialized( + atclient_delete_request_options *options) { + /* + * 1. Validate arguments + */ + if (options == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "atclient_delete_request_options_is_skip_shared_by_check_initialized: Invalid arguments\n"); + return false; + } + + /* + * 2. Check if the skip_shared_by_check is initialized + */ + return options->_initialized_fields[ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INDEX] & + ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INITIALIZED; +} + +static void +atclient_delete_request_options_skip_shared_by_check_set_intitialized(atclient_delete_request_options *options, + const bool initialized) { + /* + * 1. Validate arguments + */ + if (options == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "atclient_delete_request_options_set_skip_shared_by_check_flag: Invalid arguments\n"); + return; + } + + /* + * 2. set initialized state + */ + if (initialized) { + options->_initialized_fields[ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INDEX] |= + ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INITIALIZED; + } else { + options->_initialized_fields[ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INDEX] &= + ~ATCLIENT_DELETE_REQUEST_OPTIONS_SKIP_SHARED_BY_CHECK_INITIALIZED; + } +} + +void atclient_delete_request_options_set_skip_shared_by_check(atclient_delete_request_options *options, + const bool option) { + /* + * 1. Validate arguments + */ + if (options == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "atclient_delete_request_options_unset_skip_shared_by_check_flag: Invalid arguments\n"); + return; + } + + /* + * 2. Unset pre-exsting value (if exists) + */ + if (atclient_delete_request_options_is_skip_shared_by_check_flag_initialized(options)) { + atclient_delete_request_options_unset_skip_shared_by_check(options); + } + + /* + * 3. Set value and set intiliazed to true + */ + memcpy(&(options->skip_shared_by_check), &option, sizeof(option)); + atclient_delete_request_options_skip_shared_by_check_set_intitialized(options, true); +} + +void atclient_delete_request_options_unset_skip_shared_by_check(atclient_delete_request_options *options) { + /* + * 1. Validate arguments + */ + if (options == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "atclient_delete_request_options_unset_skip_shared_by_check_flag: Invalid arguments\n"); + return; + } + + options->skip_shared_by_check = false; + atclient_delete_request_options_skip_shared_by_check_set_intitialized(options, false); +} + void atclient_get_atkeys_request_options_init(atclient_get_atkeys_request_options *options) { /* * 1. Validate arguments @@ -1435,20 +1549,20 @@ void atclient_get_atkeys_request_options_unset_show_hidden(atclient_get_atkeys_r atclient_get_atkeys_request_options_set_show_hidden_initialized(options, false); } -void atclient_pkam_authenticate_options_init(atclient_pkam_authenticate_options *options) { - memset(options, 0, sizeof(atclient_pkam_authenticate_options)); - options->atdirectory_host = ATCLIENT_PKAM_AUTHENTICATE_DEFAULT_AT_DIRECTORY_HOST; - options->atdirectory_port = ATCLIENT_PKAM_AUTHENTICATE_DEFAULT_AT_DIRECTORY_PORT; +void atclient_authenticate_options_init(atclient_authenticate_options *options) { + memset(options, 0, sizeof(atclient_authenticate_options)); + options->atdirectory_host = ATCLIENT_AUTHENTICATE_DEFAULT_ROOT_SERVER_HOST; + options->atdirectory_port = ATCLIENT_AUTHENTICATE_DEFAULT_ROOT_SERVER_PORT; options->atserver_host = NULL; options->atserver_port = 0; } -void atclient_pkam_authenticate_options_free(atclient_pkam_authenticate_options *options) { +void atclient_authenticate_options_free(atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { - atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_pkam_authenticate_options_free: Invalid arguments\n"); + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_authenticate_options_free: Invalid arguments\n"); return; } @@ -1456,31 +1570,30 @@ void atclient_pkam_authenticate_options_free(atclient_pkam_authenticate_options * 2. Free options */ - if (atclient_pkam_authenticate_options_is_atdirectory_host_initialized(options)) { - atclient_pkam_authenticate_options_unset_at_directory_host(options); + if (atclient_authenticate_options_is_atdirectory_host_initialized(options)) { + atclient_authenticate_options_unset_at_directory_host(options); } - if (atclient_pkam_authenticate_options_is_atdirectory_port_initialized(options)) { - atclient_pkam_authenticate_options_unset_at_directory_port(options); + if (atclient_authenticate_options_is_atdirectory_port_initialized(options)) { + atclient_authenticate_options_unset_at_directory_port(options); } - if (atclient_pkam_authenticate_options_is_atserver_host_initialized(options)) { - atclient_pkam_authenticate_options_unset_atserver_host(options); + if (atclient_authenticate_options_is_atserver_host_initialized(options)) { + atclient_authenticate_options_unset_atserver_host(options); } - if (atclient_pkam_authenticate_options_is_atserver_port_initialized(options)) { - atclient_pkam_authenticate_options_unset_atserver_port(options); + if (atclient_authenticate_options_is_atserver_port_initialized(options)) { + atclient_authenticate_options_unset_atserver_port(options); } } -bool atclient_pkam_authenticate_options_is_atdirectory_host_initialized( - const atclient_pkam_authenticate_options *options) { +bool atclient_authenticate_options_is_atdirectory_host_initialized(const atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_is_atdirectory_host_initialized: " + "atclient_authenticate_options_is_atdirectory_host_initialized: " "Invalid arguments\n"); return false; } @@ -1488,18 +1601,17 @@ bool atclient_pkam_authenticate_options_is_atdirectory_host_initialized( /* * 2. Check if the at directory host is initialized */ - return options->_initialized_fields[ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INDEX] & - ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INITIALIZED; + return options->_initialized_fields[ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INDEX] & + ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_HOST_INITIALIZED; } -bool atclient_pkam_authenticate_options_is_atdirectory_port_initialized( - const atclient_pkam_authenticate_options *options) { +bool atclient_authenticate_options_is_atdirectory_port_initialized(const atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_is_atdirectory_port_initialized: " + "atclient_authenticate_options_is_atdirectory_port_initialized: " "Invalid arguments\n"); return false; } @@ -1507,18 +1619,17 @@ bool atclient_pkam_authenticate_options_is_atdirectory_port_initialized( /* * Check if the at directory port is initialized */ - return options->_initialized_fields[ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INDEX] & - ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INITIALIZED; + return options->_initialized_fields[ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INDEX] & + ATCLIENT_AUTHENTICATE_OPTIONS_AT_DIRECTORY_PORT_INITIALIZED; } -bool atclient_pkam_authenticate_options_is_atserver_host_initialized( - const atclient_pkam_authenticate_options *options) { +bool atclient_authenticate_options_is_atserver_host_initialized(const atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_is_atserver_host_initialized: " + "atclient_authenticate_options_is_atserver_host_initialized: " "Invalid arguments\n"); return false; } @@ -1526,18 +1637,17 @@ bool atclient_pkam_authenticate_options_is_atserver_host_initialized( /* * Check if the atserver host is initialized */ - return options->_initialized_fields[ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INDEX] & - ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INITIALIZED; + return options->_initialized_fields[ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INDEX] & + ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_HOST_INITIALIZED; } -bool atclient_pkam_authenticate_options_is_atserver_port_initialized( - const atclient_pkam_authenticate_options *options) { +bool atclient_authenticate_options_is_atserver_port_initialized(const atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_is_atserver_port_initialized: " + "atclient_authenticate_options_is_atserver_port_initialized: " "Invalid arguments\n"); return false; } @@ -1545,73 +1655,73 @@ bool atclient_pkam_authenticate_options_is_atserver_port_initialized( /* * Check if the atserver port is initialized */ - return options->_initialized_fields[ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INDEX] & - ATCLIENT_PKAM_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INITIALIZED; + return options->_initialized_fields[ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INDEX] & + ATCLIENT_AUTHENTICATE_OPTIONS_ATSERVER_PORT_INITIALIZED; } -void atclient_pkam_authenticate_options_unset_at_directory_host(atclient_pkam_authenticate_options *options) { +void atclient_authenticate_options_unset_at_directory_host(atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_unset_at_directory_host: Invalid arguments\n"); + "atclient_authenticate_options_unset_at_directory_host: Invalid arguments\n"); return; } /* * 2. Unsetat directory */ - if (atclient_pkam_authenticate_options_is_atdirectory_host_initialized(options)) { + if (atclient_authenticate_options_is_atdirectory_host_initialized(options)) { free(options->atdirectory_host); } options->atdirectory_host = NULL; } -void atclient_pkam_authenticate_options_unset_at_directory_port(atclient_pkam_authenticate_options *options) { +void atclient_authenticate_options_unset_at_directory_port(atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_unset_at_directory_port: Invalid arguments\n"); + "atclient_authenticate_options_unset_at_directory_port: Invalid arguments\n"); return; } options->atdirectory_port = 64; } -void atclient_pkam_authenticate_options_unset_atserver_host(atclient_pkam_authenticate_options *options) { +void atclient_authenticate_options_unset_atserver_host(atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_unset_atserver_host: Invalid arguments\n"); + "atclient_authenticate_options_unset_atserver_host: Invalid arguments\n"); return; } /* * 2. Unset atserver host */ - if (atclient_pkam_authenticate_options_is_atserver_host_initialized(options)) { + if (atclient_authenticate_options_is_atserver_host_initialized(options)) { free(options->atserver_host); } options->atserver_host = NULL; } -void atclient_pkam_authenticate_options_unset_atserver_port(atclient_pkam_authenticate_options *options) { +void atclient_authenticate_options_unset_atserver_port(atclient_authenticate_options *options) { /* * 1. Validate arguments */ if (options == NULL) { atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_unset_atserver_port: Invalid arguments\n"); + "atclient_authenticate_options_unset_atserver_port: Invalid arguments\n"); return; } options->atserver_port = 0; } -int atclient_pkam_authenticate_options_set_at_directory_host(atclient_pkam_authenticate_options *options, - char *atdirectory_host) { +int atclient_authenticate_options_set_at_directory_host(atclient_authenticate_options *options, + char *atdirectory_host) { int ret = 1; /* @@ -1620,15 +1730,15 @@ int atclient_pkam_authenticate_options_set_at_directory_host(atclient_pkam_authe if (options == NULL) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_set_at_directory_host: Invalid arguments\n"); + "atclient_authenticate_options_set_at_directory_host: Invalid arguments\n"); return ret; } /* * 2. Unset at directory host, if initialized */ - if (atclient_pkam_authenticate_options_is_atdirectory_host_initialized(options)) { - atclient_pkam_authenticate_options_unset_at_directory_host(options); + if (atclient_authenticate_options_is_atdirectory_host_initialized(options)) { + atclient_authenticate_options_unset_at_directory_host(options); } /* @@ -1640,8 +1750,7 @@ int atclient_pkam_authenticate_options_set_at_directory_host(atclient_pkam_authe exit: { return ret; } } -int atclient_pkam_authenticate_options_set_at_directory_port(atclient_pkam_authenticate_options *options, - int atdirectory_port) { +int atclient_authenticate_options_set_at_directory_port(atclient_authenticate_options *options, int atdirectory_port) { int ret = 1; /* @@ -1650,15 +1759,15 @@ int atclient_pkam_authenticate_options_set_at_directory_port(atclient_pkam_authe if (options == NULL) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_set_at_directory_port: Invalid arguments\n"); + "atclient_authenticate_options_set_at_directory_port: Invalid arguments\n"); return ret; } /* * 2. Unset at directory port, if initialized */ - if (atclient_pkam_authenticate_options_is_atdirectory_port_initialized(options)) { - atclient_pkam_authenticate_options_unset_at_directory_host(options); + if (atclient_authenticate_options_is_atdirectory_port_initialized(options)) { + atclient_authenticate_options_unset_at_directory_host(options); } /* @@ -1670,8 +1779,7 @@ int atclient_pkam_authenticate_options_set_at_directory_port(atclient_pkam_authe exit: { return ret; } } -int atclient_pkam_authenticate_options_set_atserver_host(atclient_pkam_authenticate_options *options, - char *atserver_host) { +int atclient_authenticate_options_set_atserver_host(atclient_authenticate_options *options, char *atserver_host) { int ret = 1; /* @@ -1680,15 +1788,15 @@ int atclient_pkam_authenticate_options_set_atserver_host(atclient_pkam_authentic if (options == NULL) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_set_atserver_host: Invalid arguments\n"); + "atclient_authenticate_options_set_atserver_host: Invalid arguments\n"); return ret; } /* * 2. Unset the atserver host, if initialized */ - if (atclient_pkam_authenticate_options_is_atserver_host_initialized(options)) { - atclient_pkam_authenticate_options_unset_atserver_host(options); + if (atclient_authenticate_options_is_atserver_host_initialized(options)) { + atclient_authenticate_options_unset_atserver_host(options); } /* @@ -1702,8 +1810,7 @@ int atclient_pkam_authenticate_options_set_atserver_host(atclient_pkam_authentic exit: { return ret; } } -int atclient_pkam_authenticate_options_set_atserver_port(atclient_pkam_authenticate_options *options, - int atserver_port) { +int atclient_authenticate_options_set_atserver_port(atclient_authenticate_options *options, int atserver_port) { int ret = 1; /* @@ -1712,15 +1819,15 @@ int atclient_pkam_authenticate_options_set_atserver_port(atclient_pkam_authentic if (options == NULL) { ret = 1; atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, - "atclient_pkam_authenticate_options_set_atserver_port: Invalid arguments\n"); + "atclient_authenticate_options_set_atserver_port: Invalid arguments\n"); return ret; } /* * 2. Unset the atserver port, if initialized */ - if (atclient_pkam_authenticate_options_is_atserver_port_initialized(options)) { - atclient_pkam_authenticate_options_unset_atserver_host(options); + if (atclient_authenticate_options_is_atserver_port_initialized(options)) { + atclient_authenticate_options_unset_atserver_host(options); } /* diff --git a/packages/atcommons/CMakeLists.txt b/packages/atcommons/CMakeLists.txt new file mode 100644 index 00000000..89f101b6 --- /dev/null +++ b/packages/atcommons/CMakeLists.txt @@ -0,0 +1,120 @@ +# Configurable options +option(ATCOMMONS_BUILD_TESTS "Build tests for atcommons" OFF) + +# Set include directory and file sources +set(ATCOMMONS_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/include) +set( + ATCOMMONS_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/enroll/enroll_operation.c + ${CMAKE_CURRENT_LIST_DIR}/src/enroll/enroll_status.c + ${CMAKE_CURRENT_LIST_DIR}/src/enroll/enroll_namespace.c + ${CMAKE_CURRENT_LIST_DIR}/src/enroll/enroll_params.c + ${CMAKE_CURRENT_LIST_DIR}/src/command_builders/enroll_command_builder.c + ${CMAKE_CURRENT_LIST_DIR}/tests +) + +# Project setup +cmake_minimum_required(VERSION 3.24) +set(CMAKE_C_STANDARD 99) +cmake_policy(SET CMP0135 NEW) + +## not adding the esp target yet + +project( + atcommons + VERSION 0.0.1 + DESCRIPTION "Atsign technology common utilities and implementations" + HOMEPAGE_URL https://atsign.com + LANGUAGES C +) + +if (NOT ESP_PLATFORM) + include(GNUInstallDirs) + + # Determine if atchops is being built as a subproject using add_subdirectory() + if (NOT DEFINED ATCOMMONS_AS_SUBPROJECT) + set(ATCOMMONS_AS_SUBPROJECT ON) + + if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(ATCOMMONS_AS_SUBPROJECT OFF) + endif () + endif () + + message(STATUS "[ATCOMMONS] ATCOMMONS_AS_SUBPROJECT: ${ATCOMMONS_AS_SUBPROJECT}") + + # Import cjson + if (NOT TARGET cjson) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/find_cjson.cmake) + endif () + + # Import atlogger + if (NOT TARGET atlogger) + set(atlogger_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../atlogger) + include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/atlogger.cmake) + endif () + + # Create library targets + if (NOT TARGET atcommons) + add_library(${PROJECT_NAME} STATIC ${ATCOMMONS_SOURCES}) + add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + endif () + + # LINK + # Link include headers to library targets + target_include_directories( + ${PROJECT_NAME} + PUBLIC + $ + $ + $ + ) + + # Link dependencies to library targets + set(ATCOMMONS_INSTALL_TARGETS cjson atlogger) + target_link_libraries(${PROJECT_NAME} PUBLIC ${ATCOMMONS_INSTALL_TARGETS}) + + # INSTALL + # Install the include headers + install( + DIRECTORY ${ATCOMMONS_INCLUDE_DIR}/${PROJECT_NAME} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install( + FILES ${cJSON_SOURCE_DIR}/cJSON.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + # Install libraries to config target + install( + TARGETS ${PROJECT_NAME} ${ATCOMMONS_INSTALL_TARGETS} + EXPORT ${PROJECT_NAME}-config + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + + # EXPORT + if (NOT ATCOMMONS_AS_SUBPROJECT AND ATCOMMONS_EXPORT) + # Export the library + export(PACKAGE ${PROJECT_NAME}) + # Install as a config.make + install( + EXPORT ${PROJECT_NAME}-config + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} + FILE ${PROJECT_NAME}-config.cmake + ) + + #export the config.cmake + export( + EXPORT ${PROJECT_NAME}-config + NAMESPACE ${PROJECT_NAME}:: + FILE "cmake/${PROJECT_NAME}-config.cmake" + ) + endif () + + if (ATCOMMONS_BUILD_TESTS) + message("[ATCOMMONS] Building tests") + enable_testing() + add_subdirectory(tests) + endif () +endif () \ No newline at end of file diff --git a/packages/atcommons/include/atcommons/cjson.h b/packages/atcommons/include/atcommons/cjson.h new file mode 100644 index 00000000..249e1f84 --- /dev/null +++ b/packages/atcommons/include/atcommons/cjson.h @@ -0,0 +1,10 @@ +#ifndef ATCOMMONS_CJSON_H +#define ATCOMMONS_CJSON_H + +#if defined(CONFIG_IDF_TARGET_ESP32) +#include +#else +#include "cJSON.h" +#endif + +#endif diff --git a/packages/atcommons/include/atcommons/enroll_command_builder.h b/packages/atcommons/include/atcommons/enroll_command_builder.h new file mode 100644 index 00000000..1e71fde5 --- /dev/null +++ b/packages/atcommons/include/atcommons/enroll_command_builder.h @@ -0,0 +1,24 @@ +#ifndef ATCOMMONS_ENROLL_VERB_BUILDER_H +#define ATCOMMONS_ENROLL_VERB_BUILDER_H + +#include "atcommons/enroll_operation.h" +#include "atcommons/enroll_params.h" +#include + +/** + * @brief Constructs an enroll command based on the args provided. Currently only supports enroll:request + * + * @note To caclulate the buffer size needed to hold the command, call this method with command = NULL and cmd_size = 0 + * + * @param command A pointer to store the constructed enroll command. Should be allocated of size + * ENROLL_COMMAND_MAX_LENGTH + * @param cmd_size Size of the command buffer + * @param cmd_len A pointer to populate the length of the enroll command written into the command buffer + * @param operation Specifies the type of enroll operation (request/approve/deny/revoke/revoke/list/delete) + * @param params A pointer to the enroll_params_t struct that holds the parameters for the current enrollment operations + * @return 0 on success, non-zero indicating failure + */ +int atcommons_build_enroll_command(char *command, size_t cmd_size, size_t *cmd_len, + atcommons_enroll_operation_t operation, const atcommons_enroll_params_t *params); + +#endif diff --git a/packages/atcommons/include/atcommons/enroll_namespace.h b/packages/atcommons/include/atcommons/enroll_namespace.h new file mode 100644 index 00000000..28e411f8 --- /dev/null +++ b/packages/atcommons/include/atcommons/enroll_namespace.h @@ -0,0 +1,62 @@ +#ifndef ATCOMMONS_ENROLL_NAMESPACE_H +#define ATCOMMONS_ENROLL_NAMESPACE_H + +#include + +typedef struct { + char *name; + char *access; +} atcommons_enroll_namespace_t; + +typedef struct { + size_t length; + atcommons_enroll_namespace_t *namespaces[]; +} atcommons_enroll_namespace_list_t; + +/** + * @brief serializes enroll_namespace struct to JSON string + * + * Note: To caclulate expected length, use method with ns_str set to null and ns_str_size set to 0 + * + * @param ns_str pointer to a char buffer where the JSON string will be stored + * @param ns_str_size size of the ns_str char buffer, to ensure safe writing + * @param ns_str_len pointer to where the length of the JSON string will be + * stored by the method + * @param ns enroll_namespace struct which needs to be serialized + * @return int 0 on success, non-zero int on failure + */ +int atcommons_enroll_namespace_to_json(char *ns_str, const size_t ns_str_size, size_t *ns_str_len, + const atcommons_enroll_namespace_t *ns); + +/** + * @brief serialises a list of enroll_namespace[s] to JSON string + * + * @param ns_list_string pointer to the string buffer where the JSON string + * should be stored + * @param ns_list_str_len pointer to store the length of the generated + * enroll_namepace_list JSON string + * @param ns_list pointer to the enroll_namespace_list struct that needs to be + * serialized + * @return int 0 on success, non-zero int on failure + */ +int atcommons_enroll_namespace_list_to_json(char **ns_list_string, size_t *ns_list_str_len, + const atcommons_enroll_namespace_list_t *ns_list); + +/** + * @brief appends an enroll_namespace struct to an enroll_namespace_list struct. + * Realloc's new memry required to append the new enroll_namespace + * + * Note: It is recommended to use this method to append an enroll_namespace + * struct as this method sets necessary interal params that will be used while + * serializing the enroll_namespace_list to JSON string + * + * @param ns_list double pointer to the enroll_namespace_list struct to which + * the new namespace should be appended + * @param ns pointer to the enroll_namespace struct that needs to be appended to + * the list + * @return int 0 on success, non-zero int on failure + */ +int atcommons_enroll_namespace_list_append(atcommons_enroll_namespace_list_t **ns_list, + atcommons_enroll_namespace_t *ns); + +#endif diff --git a/packages/atcommons/include/atcommons/enroll_operation.h b/packages/atcommons/include/atcommons/enroll_operation.h new file mode 100644 index 00000000..9c1aab9d --- /dev/null +++ b/packages/atcommons/include/atcommons/enroll_operation.h @@ -0,0 +1,25 @@ +#ifndef ATCOMMONS_ENROLL_OPERATION_H +#define ATCOMMONS_ENROLL_OPERATION_H + +#define MAX_ENROLL_OPERATION_STRING_LEN 8 + +typedef enum { + atcommons_apkam_request, + atcommons_apkam_approve, + atcommons_apkam_deny, + atcommons_apkam_revoke, + atcommons_apkam_unrevoke, + atcommons_apkam_list, + atcommons_apkam_delete +} atcommons_enroll_operation_t; + +/** + * @brief Parses enroll operation type enroll_operation_t and converts that into a string + * + * @param op_name Double pointer to populate the enroll operation name as String(char *) + * @param e_op enroll operation as enum enroll_operation_t + * @return int 0 on success, non-zero on failure + */ +int atcommons_enroll_operation_to_string(char **op_name, atcommons_enroll_operation_t e_op); + +#endif \ No newline at end of file diff --git a/packages/atcommons/include/atcommons/enroll_params.h b/packages/atcommons/include/atcommons/enroll_params.h new file mode 100644 index 00000000..ccde2111 --- /dev/null +++ b/packages/atcommons/include/atcommons/enroll_params.h @@ -0,0 +1,41 @@ +#ifndef ATCOMMONS_ENROLL_PARAMS_H +#define ATCOMMONS_ENROLL_PARAMS_H + +#include "atcommons/enroll_namespace.h" + +typedef struct { + char *enrollment_id; + char *app_name; + char *device_name; + char *otp; + atcommons_enroll_namespace_list_t + *ns_list; // list of enroll namespaces and their required access for current enrollment + unsigned char *apkam_public_key; + unsigned char *encrypted_default_encryption_private_key; // apkam symmetric key encrypted default enc private key + unsigned char *encrypted_self_encryption_key; // apkam symmetric key encrypted seld enc key + unsigned char *encrypted_apkam_symmetric_key; + int apkam_keys_expiry_in_millis; +} atcommons_enroll_params_t; + +/** + * @brief Initializes the enroll_params_t struct + * + * @param ep pointer to the enroll params struct that is to be initialized + * @return int 0 on success, non-zero int on failure + */ +int atcommons_enroll_params_init(atcommons_enroll_params_t *ep); + +/** + * @brief Converts the parameters in an enroll_params_t struct to a json encoded string + * + * Note: To calculate expected string len, use method with json_string set to NULL and json_string_size set to 0 + * + * @param json_string Double pointer to store the json encoded string of provided enroll params + * @param json_string_size Allocated memory size for json_string buffer + * @param json_string_len Actual string length written into json_string buffer + * @param ep Pointer to the enroll_params_t struct whose values need to be converted to a json string + * @return int 0 for success, non-zero int for failure + */ +int atcommons_enroll_params_to_json(char **json_string, size_t *json_string_len, const atcommons_enroll_params_t *ep); + +#endif diff --git a/packages/atcommons/include/atcommons/enroll_status.h b/packages/atcommons/include/atcommons/enroll_status.h new file mode 100644 index 00000000..0f4761cd --- /dev/null +++ b/packages/atcommons/include/atcommons/enroll_status.h @@ -0,0 +1,23 @@ +#ifndef ATCOMMONS_ENROLL_STATUS_H +#define ATCOMMONS_ENROLL_STATUS_H + +#define ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN 10 + +typedef enum { + atcommons_enroll_status_pending, + atcommons_enroll_status_approved, + atcommons_enroll_status_denied, + atcommons_enroll_status_revoked, + atcommons_enroll_status_expired +} atcommons_enroll_status_t; + +/** + * @brief Parses an enroll_status_t enum value and converts it to string + * + * @param status Pointer to populate the enroll status value as string (char *) + * @param es enroll status value of type eroll_status_t + * @return int 0 on success, non-zero int on failure + */ +int enroll_status_to_string(char *status, atcommons_enroll_status_t es); + +#endif \ No newline at end of file diff --git a/packages/atcommons/src/command_builders/enroll_command_builder.c b/packages/atcommons/src/command_builders/enroll_command_builder.c new file mode 100644 index 00000000..74745a84 --- /dev/null +++ b/packages/atcommons/src/command_builders/enroll_command_builder.c @@ -0,0 +1,89 @@ +#include "atcommons/enroll_command_builder.h" +#include "atcommons/enroll_operation.h" +#include "atcommons/enroll_params.h" +#include "atlogger/atlogger.h" + +#include +#include +#include +#include + +#define ENROLL_PREFIX "enroll:" +#define TAG "enroll command builder" + +int atcommons_build_enroll_command(char *command, const size_t cmd_size, size_t *cmd_len, + const atcommons_enroll_operation_t operation, const atcommons_enroll_params_t *params) { + int ret = 0; + int cur_len = 0; + char *params_json = NULL, *e_op = NULL; + size_t params_json_len = 0; + + e_op = malloc(sizeof(char) * MAX_ENROLL_OPERATION_STRING_LEN); + if (e_op == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate memory for enroll op string\n"); + ret = -1; + goto free_params_json; + } + memset(e_op, 0, sizeof(char) * MAX_ENROLL_OPERATION_STRING_LEN); + + // A, B, C and D are used ONLY to calculate the expected command length + if (command == NULL && cmd_size == 0) { + /* + * A. Caclculate enroll prefix len + */ + cur_len += snprintf(NULL, 0, "%s", ENROLL_PREFIX); + + /* + * B. Calculate enroll operation len + */ + if ((ret = atcommons_enroll_operation_to_string(&e_op, operation)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_atcommons_enroll_operation_to_string: %d\n", ret); + goto free_enroll_op; + } + cur_len += snprintf(NULL, 0, "%s:", e_op); + + /* + * C. Calculate enroll params json len + */ + atcommons_enroll_params_to_json(NULL, ¶ms_json_len, params); // fetch 'enroll_params_json' length + cur_len += params_json_len + 3; // +2 for \r\n\0 + + /* + * D. Populate 'cmd_len' with the calculated commmand length + */ + *cmd_len = cur_len; + ret = 1; // setting a non-zero exit code to ensure this if-clause is only used for commadn len calculation + goto free_enroll_op; + } + + /* + * 1. Write the enroll prefix into command + */ + cur_len += snprintf(command, cmd_size, "%s", ENROLL_PREFIX); + + /* + * 2. Convert enroll operation to string, then append to command + */ + if ((ret = atcommons_enroll_operation_to_string(&e_op, operation)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_operation_to_string: %d\n", ret); + ret = 1; + return ret; + } + cur_len += snprintf(command + cur_len, cmd_size, "%s:", e_op); + + /* + * 3. Convert enroll params to JSON, then append to command + */ + if ((ret = atcommons_enroll_params_to_json(¶ms_json, ¶ms_json_len, params)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_params_to_json: %d\n", ret); + goto exit; + } + + // populate enroll_params_json into 'command' + cur_len += snprintf(command + cur_len, cmd_size, "%s\r\n", params_json); + *cmd_len = cur_len; + +free_enroll_op: { free(e_op); } +free_params_json: { free(params_json); } +exit: { return ret; } +} diff --git a/packages/atcommons/src/enroll/enroll_namespace.c b/packages/atcommons/src/enroll/enroll_namespace.c new file mode 100644 index 00000000..26c02612 --- /dev/null +++ b/packages/atcommons/src/enroll/enroll_namespace.c @@ -0,0 +1,84 @@ +#include "atcommons/enroll_namespace.h" + +#include "cJSON.h" + +#include +#include +#include + +#include + +#define TAG "enroll_namespace" + +int atcommons_enroll_namespace_list_append(atcommons_enroll_namespace_list_t **ns_list, + atcommons_enroll_namespace_t *ns) { + // allocate enough memory for enroll_namespace_list struct, and the number of atcommons_enroll_namespace_t structs + // that are in the list + atcommons_enroll_namespace_list_t *temp = + realloc(*ns_list, sizeof(atcommons_enroll_namespace_list_t) + + sizeof(atcommons_enroll_namespace_t) * ((*ns_list)->length + 1)); + + if (temp == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Unable to realloc memory for enroll namespace list\n"); + return -1; + } + + // Add the new namespace to the end of the list + temp->namespaces[temp->length] = ns; + temp->length++; + + // Update the original ns_list to point to the new (reallocated) memory + *ns_list = temp; + + return 0; +} + +int atcommons_enroll_namespace_to_json(char *ns_str, const size_t ns_str_size, size_t *ns_str_len, + const atcommons_enroll_namespace_t *ns) { + if (ns == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "ns(namespace) cannot be null\n"); + return -1; + } + if (ns_str == NULL && ns_str_size == 0) { + *ns_str_len = snprintf(NULL, 0, "{\"%s\":\"%s\"}", ns->name, ns->access) + 1; // +1 for \0 + } + + *ns_str_len = snprintf(ns_str, ns_str_size, "{\"%s\":\"%s\"}", ns->name, ns->access); + + return 0; +} + +int atcommons_enroll_namespace_list_to_json(char **ns_list_string, size_t *ns_list_str_len, + const atcommons_enroll_namespace_list_t *ns_list) { + if (ns_list == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "ns_list(namespace list) cannot be null\n"); + return -1; + } + if (ns_list_str_len == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "ns_list_str_len(namespace_list string length) cannot be null\n"); + return -1; + } + // Create a new cJSON object + cJSON *json_obj = cJSON_CreateObject(); + if (json_obj == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to create JSON object\n"); + return -1; + } + + for (size_t ns_elmnt = 0; ns_elmnt < ns_list->length; ns_elmnt++) { + cJSON_AddStringToObject(json_obj, ns_list->namespaces[ns_elmnt]->name, ns_list->namespaces[ns_elmnt]->access); + } + + *ns_list_string = cJSON_PrintUnformatted(json_obj); + if (*ns_list_string == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to print JSON\n"); + cJSON_Delete(json_obj); + return -1; + } + if (ns_list_str_len != NULL) { + *ns_list_str_len = strlen(*ns_list_string); + } + + cJSON_Delete(json_obj); + return 0; +} diff --git a/packages/atcommons/src/enroll/enroll_operation.c b/packages/atcommons/src/enroll/enroll_operation.c new file mode 100644 index 00000000..2c8e6f9e --- /dev/null +++ b/packages/atcommons/src/enroll/enroll_operation.c @@ -0,0 +1,48 @@ +#include "atcommons/enroll_operation.h" + +#include +#include +#include + +#define ATCOMMONS_ENROLL_OPERATION_REQUEST "request" +#define ATCOMMONS_ENROLL_OPERATION_APPROVE "approve" +#define ATCOMMONS_ENROLL_OPERATION_DENY "deny" +#define ATCOMMONS_ENROLL_OPERATION_REVOKE "revoke" +#define ATCOMMONS_ENROLL_OPERATION_UNREVOKE "unrevoke" +#define ATCOMMONS_ENROLL_OPERATION_LIST "list" +#define ATCOMMONS_ENROLL_OPERATION_DELETE "delete" + +int atcommons_enroll_operation_to_string(char **op_name, const atcommons_enroll_operation_t e_op) { + int ret = 0; + if (op_name == NULL) { + ret = -1; + return ret; + } + + switch (e_op) { + case atcommons_apkam_request: + strcpy(*op_name, ATCOMMONS_ENROLL_OPERATION_REQUEST); + break; + case atcommons_apkam_approve: + strcpy(*op_name, ATCOMMONS_ENROLL_OPERATION_APPROVE); + break; + case atcommons_apkam_deny: + strcpy(*op_name, ATCOMMONS_ENROLL_OPERATION_DENY); + break; + case atcommons_apkam_revoke: + strcpy(*op_name, ATCOMMONS_ENROLL_OPERATION_REVOKE); + break; + case atcommons_apkam_unrevoke: + strcpy(*op_name, ATCOMMONS_ENROLL_OPERATION_UNREVOKE); + break; + case atcommons_apkam_list: + strcpy(*op_name, ATCOMMONS_ENROLL_OPERATION_LIST); + break; + case atcommons_apkam_delete: + strcpy(*op_name, ATCOMMONS_ENROLL_OPERATION_DELETE); + break; + default: + ret = 1; + } + return ret; +} diff --git a/packages/atcommons/src/enroll/enroll_params.c b/packages/atcommons/src/enroll/enroll_params.c new file mode 100644 index 00000000..27745d71 --- /dev/null +++ b/packages/atcommons/src/enroll/enroll_params.c @@ -0,0 +1,118 @@ +#include "atcommons/enroll_params.h" + +#include "cJSON.h" + +#include +#include +#include +#include +#include + +#define ENROLLMENT_ID "enrollmentId" +#define APP_NAME "appName" +#define DEVICE_NAME "deviceName" +#define OTP "otp" +#define NAMESPACES "namespaces" +#define APKAM_PUBLIC_KEY "apkamPublicKey" +#define ENCRYPTED_DEFAULT_ENCRYPTION_PRIVATE_KEY "encryptedDefaultEncryptionPrivateKey" +#define ENCRYPTED_DEFAULT_SELF_ENCRYPTION_KEY "encryptedDefaultSelfEncryptionKey" +#define ENCRYPTED_APKAM_SYMMETRIC_KEY "encryptedAPKAMSymmetricKey" +#define APKAM_KEYS_EXPIRY "apkamKeysExpiryInMillis" // in milliseconds + +#define TAG "enroll_params" + +int atcommons_enroll_params_init(atcommons_enroll_params_t *ep) { + /* + * 1. Validate arguments + */ + if (ep == NULL) { + return -1; + } + + /* + * 2. Initialize + */ + memset(ep, 0, sizeof(atcommons_enroll_params_t)); + + return 0; +} + +int atcommons_enroll_params_to_json(char **json_string, size_t *json_string_len, const atcommons_enroll_params_t *ep) { + int ret = 0; + + if (ep == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "enroll params cannot be null for atcommons_enroll_params_to_json\n"); + ret = -1; + return ret; + } + + cJSON *json_object = cJSON_CreateObject(); + if (json_object == NULL) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to create JSON object\n"); + ret = -1; + return ret; + } + + // Add each parameter to JSON only if it is not NULL + if (ep->enrollment_id != NULL) { + cJSON_AddStringToObject(json_object, ENROLLMENT_ID, ep->enrollment_id); + } + + if (ep->app_name != NULL) { + cJSON_AddStringToObject(json_object, APP_NAME, ep->app_name); + } + + if (ep->device_name != NULL) { + cJSON_AddStringToObject(json_object, DEVICE_NAME, ep->device_name); + } + + if (ep->otp != NULL) { + cJSON_AddStringToObject(json_object, OTP, ep->otp); + } + + char *ns_json = NULL; + // Ensure ns_list is not NULL before accessing namespaces + if (ep->ns_list != NULL && ep->ns_list->length > 0) { + size_t ns_list_str_len = 0; + if ((ret = atcommons_enroll_namespace_list_to_json(&ns_json, &ns_list_str_len, ep->ns_list)) != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, + "enroll_namespace_list serialization failed. atcommons_enroll_namespace_list_to_json: %d\n", ret); + ret = 1; + goto exit; + } + cJSON_AddRawToObject(json_object, NAMESPACES, ns_json); + } + + // Add Base64-encoded strings directly to JSON + if (ep->apkam_public_key != NULL) { + cJSON_AddStringToObject(json_object, APKAM_PUBLIC_KEY, (const char *)ep->apkam_public_key); + } + + if (ep->encrypted_default_encryption_private_key != NULL) { + cJSON_AddStringToObject(json_object, ENCRYPTED_DEFAULT_ENCRYPTION_PRIVATE_KEY, + (const char *)ep->encrypted_default_encryption_private_key); + } + + if (ep->encrypted_self_encryption_key != NULL) { + cJSON_AddStringToObject(json_object, ENCRYPTED_DEFAULT_SELF_ENCRYPTION_KEY, + (const char *)ep->encrypted_self_encryption_key); + } + + if (ep->encrypted_apkam_symmetric_key != NULL) { + cJSON_AddStringToObject(json_object, ENCRYPTED_APKAM_SYMMETRIC_KEY, + (const char *)ep->encrypted_apkam_symmetric_key); + } + // pass memory ownership of the json string to the caller + if (json_string != NULL) { + *json_string = cJSON_PrintUnformatted(json_object); + } + if (json_string_len != NULL) { + *json_string_len = strlen(cJSON_PrintUnformatted(json_object)); + } + +exit: + free(ns_json); + cJSON_Delete(json_object); + return ret; +} diff --git a/packages/atcommons/src/enroll/enroll_status.c b/packages/atcommons/src/enroll/enroll_status.c new file mode 100644 index 00000000..f8cb79bc --- /dev/null +++ b/packages/atcommons/src/enroll/enroll_status.c @@ -0,0 +1,29 @@ +#include "atcommons/enroll_status.h" + +#include +#include + +int enroll_status_to_string(char *status, const atcommons_enroll_status_t es) { + int ret = 0; + if (status == NULL) { + ret = -1; + goto exit; + } + + switch (es) { + case atcommons_enroll_status_pending: + strncpy(status, "pending", ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN); + case atcommons_enroll_status_approved: + strncpy(status, "approved", ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN); + case atcommons_enroll_status_denied: + strncpy(status, "denied", ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN); + case atcommons_enroll_status_revoked: + strncpy(status, "revoked", ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN); + case atcommons_enroll_status_expired: + strncpy(status, "expired", ATCOMMONS_ENROLL_STATUS_STRING_MAX_LEN); + default: + ret = -1; + } + + exit: { return ret; } +} diff --git a/packages/atcommons/tests/CMakeLists.txt b/packages/atcommons/tests/CMakeLists.txt new file mode 100644 index 00000000..ffd13783 --- /dev/null +++ b/packages/atcommons/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories(${PROJECT_SOURCE_DIR}/src) +file(GLOB_RECURSE files ${CMAKE_CURRENT_LIST_DIR}/test_*.c) +foreach (file ${files}) + # ${filename} - without `.c` + get_filename_component(filename ${file} NAME) + string(REPLACE ".c" "" filename ${filename}) + + add_executable(${filename} ${file}) + target_link_libraries(${filename} PRIVATE atcommons) + add_test(NAME ${filename} COMMAND $) +endforeach () \ No newline at end of file diff --git a/packages/atcommons/tests/at_expect.c b/packages/atcommons/tests/at_expect.c new file mode 100644 index 00000000..8d4b314b --- /dev/null +++ b/packages/atcommons/tests/at_expect.c @@ -0,0 +1,13 @@ +#include +#include +/* + * Not a test. This is a test utility to compare expected and actual strings + */ +int atcommons_string_expect(char *actual, char *expected) { + int ret = strcmp(actual, expected); + if (ret != 0) { + printf("test failed\nexpected: %s\n*actual*: %s\n", expected, actual); + } + + return ret; +} \ No newline at end of file diff --git a/packages/atcommons/tests/test_enroll_command_builder.c b/packages/atcommons/tests/test_enroll_command_builder.c new file mode 100644 index 00000000..df390cd9 --- /dev/null +++ b/packages/atcommons/tests/test_enroll_command_builder.c @@ -0,0 +1,45 @@ +#include "at_expect.c" +#include "atcommons/enroll_command_builder.h" +#include "atcommons/enroll_namespace.h" +#include "atcommons/enroll_params.h" +#include + +#define TAG "test_enroll_command_builder" + +int main() { + int ret = 1; + + char expected_string[] = "enroll:request:{\"appName\":\"test-app\",\"deviceName\":\"test-device\",\"otp\":\"XYZABC\"," + "\"namespaces\":{\"namespace1\":\"rw\",\"namespace2\":\"r\"}}"; + atcommons_enroll_namespace_t namespace; + namespace.name = "namespace1"; + namespace.access = "rw"; + atcommons_enroll_namespace_t namespace2 = {"namespace2", "r"}; + + atcommons_enroll_namespace_list_t *ns_list = malloc(sizeof(atcommons_enroll_namespace_list_t)); + atcommons_enroll_namespace_list_append(&ns_list, &namespace); + atcommons_enroll_namespace_list_append(&ns_list, &namespace2); + + atcommons_enroll_params_t params; + atcommons_enroll_params_init(¶ms); + params.app_name = "test-app"; + params.device_name = "test-device"; + params.otp = "XYZABC"; + params.ns_list = ns_list; + + size_t cmd_size = 0; + atcommons_build_enroll_command(NULL, 0, &cmd_size, atcommons_apkam_request, ¶ms); + char *command = malloc(sizeof(char) * cmd_size); + size_t cmd_len = 0; + ret = atcommons_build_enroll_command(command, sizeof(char) * cmd_size, &cmd_len, atcommons_apkam_request, ¶ms); + if (ret != 0) { + goto exit; + } + + ret = atcommons_string_expect(command, expected_string); + +exit: { + free(command); + return ret; +} +} \ No newline at end of file diff --git a/packages/atcommons/tests/test_enroll_namespace_utils.c b/packages/atcommons/tests/test_enroll_namespace_utils.c new file mode 100644 index 00000000..860e83c1 --- /dev/null +++ b/packages/atcommons/tests/test_enroll_namespace_utils.c @@ -0,0 +1,86 @@ +#include "at_expect.c" +#include "atcommons/enroll_namespace.h" +#include "atlogger/atlogger.h" + +#include +#include + +#define TAG "test_enroll_namespace_utils.c" + +int test_enroll_namespace_to_json(); +int test_enroll_namespace_list_to_json(); + +int main() { + int ret = test_enroll_namespace_to_json(); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "%s failed\n", "test_enroll_namespace_to_json"); + return ret; + } + ret = test_enroll_namespace_list_to_json(); + return ret; +} + +int test_enroll_namespace_to_json() { + atcommons_enroll_namespace_t en; + en.name = "ns1"; + en.access = "rw"; + char en_expected_json[] = "{\"ns1\":\"rw\"}"; + + atcommons_enroll_namespace_t en2; + en2.name = "ns2"; + en2.access = "r"; + char en2_expected_json[] = "{\"ns2\":\"r\"}"; + + char *ns_json = NULL; + size_t ns_json_len = 0; + + // test enroll namespace 1 + atcommons_enroll_namespace_to_json(NULL, 0, &ns_json_len, &en); + size_t ns_json_size = sizeof(char) * ns_json_len + 1; + ns_json = malloc(ns_json_size); + int ret = atcommons_enroll_namespace_to_json(ns_json, ns_json_size, &ns_json_len, &en); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_namespace_to_json: %d\n", ret); + } + ret = atcommons_string_expect(ns_json, en_expected_json); + + // test enroll namespace 2 + memset(ns_json, 0, ns_json_size); + ns_json_len = 0; + ret = atcommons_enroll_namespace_to_json(ns_json, ns_json_size, &ns_json_len, &en2); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_namespace_to_json: %d\n", ret); + } + ret = atcommons_string_expect(ns_json, en2_expected_json); + + free(ns_json); + return ret; +} + +int test_enroll_namespace_list_to_json() { + atcommons_enroll_namespace_t en; + en.name = "ns1"; + en.access = "rw"; + + atcommons_enroll_namespace_t en2; + en2.name = "ns2"; + en2.access = "r"; + + char en_expected_json[] = "{\"ns1\":\"rw\",\"ns2\":\"r\"}"; + + atcommons_enroll_namespace_list_t *ns_list = malloc(sizeof(atcommons_enroll_namespace_list_t)); + atcommons_enroll_namespace_list_append(&ns_list, &en); + atcommons_enroll_namespace_list_append(&ns_list, &en2); + + char *ns_list_json = NULL; + size_t ns_list_json_len = 0; + + int ret = atcommons_enroll_namespace_list_to_json(&ns_list_json, &ns_list_json_len, ns_list); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_namespace_list_to_json: %d\n", ret); + } + ret = atcommons_string_expect(ns_list_json, en_expected_json); + + free(ns_list_json); + return ret; +} \ No newline at end of file diff --git a/packages/atcommons/tests/test_enroll_params.c b/packages/atcommons/tests/test_enroll_params.c new file mode 100644 index 00000000..20058aa8 --- /dev/null +++ b/packages/atcommons/tests/test_enroll_params.c @@ -0,0 +1,155 @@ +#include "atcommons/enroll_params.h" +#include "atlogger/atlogger.h" + +#include "at_expect.c" +#include + +#define TAG "test_enroll_params" + +// this test case has all params populated e.g. app-name, deice-name, ... +int test_case_1() { + // create an enroll_namespace + atcommons_enroll_namespace_t namespace; + namespace.name = "namespace1"; + namespace.access = "rw"; + + // another way to create an enroll namespace + atcommons_enroll_namespace_t namespace2 = {"namespace2", "r"}; + + atcommons_enroll_namespace_list_t *ns_list = malloc(sizeof(atcommons_enroll_namespace_list_t)); + atcommons_enroll_namespace_list_append(&ns_list, &namespace); + atcommons_enroll_namespace_list_append(&ns_list, &namespace2); + + atcommons_enroll_params_t *enroll_params = malloc(sizeof(atcommons_enroll_params_t)); + atcommons_enroll_params_init(enroll_params); + enroll_params->app_name = "test-app"; + enroll_params->device_name = "test-device"; + enroll_params->otp = "XYZABC"; + enroll_params->ns_list = ns_list; + char *expected_json = "{\"appName\":\"test-app\",\"deviceName\":\"test-device\",\"otp\":\"XYZABC\",\"namespaces\":{" + "\"namespace1\":\"rw\",\"namespace2\":\"r\"}}"; + + size_t params_json_len = 0; + char *params_json = NULL; + int ret = atcommons_enroll_params_to_json(¶ms_json, ¶ms_json_len, enroll_params); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_params_to_json returned: %d\n", ret); + return ret; + } + + ret = atcommons_string_expect(params_json, expected_json); + return ret; +} + +// this test case tries to serialize an enroll_params struct that has some null values +int test_case_2() { + char *expected_json = + "{\"appName\":\"app1\",\"deviceName\":\"rhaegar\",\"namespaces\":{\"test01\":\"rw\"},\"apkamPublicKey\":" + "\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg1THrbmEpXMDXUtci4GBNaARF2ghWYz6tC5PcO8oyjqioDwlp7lVZcufhgZGD2Dd5" + "j124vyx8t0qlTP/LObK8WvgvLOY5NqUCOgYBv0VufVzOr6xrsNKVEKC9GzMkMbUfFwBVYHeeIg3IKeGTyxB+qHQIAa2gLZCBKX8EsLTGliQmkv2J" + "96umaFTsS/juwxw9nSVpsMIwCcg6hA3njVbjR1p5o9mZ3lVw57GOHzkdyGXXBgKzNvBRXBSDOkNCulxoixrydqWD8sLc8AERQoWCUwSWITTS0YE/" + "jFL8fH2zWupjJ510JmoIf2L2MJsiFFUCtRIRTWSIHs1/cXZiIEvhQIDAQAB\"," + "\"encryptedDefaultEncryptionPrivateKey\":\"Ksq6db1VpgDFiT2E39TLyt/" + "NvvRFwlTHLRZIwPZF+RBREODSgqVmLrK5neYNQ+WFQ51h6cYtoSkaAbCpPJH8dAmbVuZGqP5LdrXBbflw0zwaJ+F/" + "qc1eP5uvE60tEko80qeDQoh15tpCny8RwhbWRxCOMaj3+n3AKOFixsz/" + "3Ka4wQxc2zwYTVoiKbrOLnsWdZnV3laEgoP56+Xd891jb3zicw50LICxU9Oj74wR1E+VyzerGTnUH+" + "CXVx7WJ0V5mkGHpac0FsXIC52cmqVQ5sI0AuiyZEV5lg2hefQZSi9Zpu/" + "B5fmxLf7WEbELRjjVUaVoDvOO7fZVFH9MCByXwJeunVzmLGXYm0YngINsA2n4uqPFY+5ku6fmVfWCr+6JLfguKUPIcdVg/OtzdC0Mv/" + "eTjg8YenazHOMPnsfIWK/Ng8aLSX3dyo3ib3BnCbwyYFlgikPv435joYlmAqrkeTYPK8Dg94wG5u/" + "1cSuqmYmKwRSEYcHAQ6Dud2o2t1jCqPhq5s+4FRTbMotUPaGiLITZKJGzDHdJB5nBdhRcjPICvsLEwq10J1lBe/b9qn47Oz3Oq8/" + "pl6ML1ZedW5MCsyjREZJZ/5/" + "oOSdbuWpB9AJNFDHS6KDUXmDWSdmtlrkjNwwmvJmxcpfIO29h+lpmVCg7ot0EYWChdqywnd9YJ+tKuRYCVvBxh+" + "LOAnEZEQiONx53EjSppCxBOyB4ZJzeCyTuGjqYP4SqGvJsCNIL5U2DPLKU2g6dVIFMQHmGzEDW4WcvGbSz62FQOSeD+" + "m5cIdPeejmTAWxl1JSXIWqMBZA6XKNUFh2L/RpYjyXuHURGiyTFv1flwB7/" + "71po1wqPrjMjiaRbRIYKcm1xLcBIvsXqPQDw0FuPYwrhzUkO0hbE+GZlBU8dnzEcP66iccbV3zJcF3mhE3OsBquRSPaqEv/" + "N5yEf8rWbREramAA0oBPwIJUaDv77JyUYaRw5wB2R3rIRgv6l1QhZAbfvaBn9bzsFL1pAoxMKLPS5x20PRHS3KUKJL7oMuAMzeYQZf4XnSW" + "mfe9YrwTRTL2beRQFqTB8wPS0n3QRWrzeTTQGg5pgVyuW/" + "2pj5zWf8C1Vm2X84rM7hB1+oy2PQxxCQCPxMNWzDkCgHzwefkB+rYhgzP2dGkRqcQUo7JGfEMgNJJ1RfW7/" + "hfr9NGXYnSREH7FTIDdXBOh6pTcG8V+BpAV7f9kknwLTqAGKGsIjw9yGd/" + "M742z1Rpq+VoeVFqXk+aZb3nellRplosO8HQrUWBRfQP2uiqO7ri0/" + "c+0McybH79yDuTyYYbMdmoU77asHsdTxgv1q9PHvcVoijysBtxT+" + "7lD0HZULe7L64V4kyRBjp5qOUiQzkcVK8XkQaCiRIlvlxeIx08FhuU9E70gOpWzyjl4esPGfHx9GWynwvXPhhQ/" + "ws8HbcXMm4rjbFfdkgs3LB6ORACXNqZDhqK1DjzOInH8SBadw4ns7YeT++1WAaPPA/" + "lAmXcZOzrvt2b6pRv6RttkMGJZhQf1PIEA2+GhTJ8ItxGnwlRpceWsuB4RRuroQZNeHD8zqbLDT7Evjcwm3EMoiMm+" + "MtNxP5hUciCZTzrNLKDIOQ00PNxSZW+yYNSHr1fx3SxJaEW4bbqZs2KyF246TOtCwSgbM+dpSrFzTh+/" + "Y6MW5dUWA36bL+HnyHuMSaIWXyj6YCgXe3fLTuEhEUmPYqAxswSkkVtxyn1PFY+L51aXXs0uzWkr00IJ3EB8tpXg4Jku+GfDZ+" + "2wdO7rDy63VHpyG9savIefXSfM8NLmYb6tEw60/" + "FznmO9G90nrXEfzo9KyfbEZ1qvDuy1d7A0GFTSuOLTFvzKzEytVfTayznpd5n3QqeU9V8uVUOwQ2We9sJ2U5ULHxMJ1gKlWpZ2mUB/" + "P3M93PUwTYp4roD147auy+3quhyIyTy3eXwqHYucFeEJ22jINov3JYus8vUWRjuU7/" + "3q3WUTGiz7fEUcr3eaPDMkSOQvUImzXWaOyJCxSC6CHpYMyyQGAW6hn35N5bYO0XyoJxQFhRwsCRa3wi9eQNSE9LizyXeLb980enIzG+" + "P44x3cd8xtpe4ABM3HkiKZAGiJ7Hz0nzs5g5wyd0mLw181nz3RBS/" + "7OvpQ22KzhohHrP6OwzXOnrRvZu62PJ4qe29ODMtecSKYFuMRTJg\",\"encryptedDefaultSelfEncryptionKey\":\"EdHYR+" + "Rol3v1pAigsuSSkOTAkcse3wHXIX9b4tZd7SBrHLXJnZt2EqLur5pIKKjD\"}"; + + // another way to create an enroll namespace + atcommons_enroll_namespace_t namespace = {"test01", "rw"}; + + atcommons_enroll_namespace_list_t *ns_list = malloc(sizeof(atcommons_enroll_namespace_list_t)); + atcommons_enroll_namespace_list_append(&ns_list, &namespace); + + atcommons_enroll_params_t *enroll_params = malloc(sizeof(atcommons_enroll_params_t)); + atcommons_enroll_params_init(enroll_params); + enroll_params->app_name = "app1"; + enroll_params->device_name = "rhaegar"; + // enroll_params->otp = "XYZABC"; + enroll_params->ns_list = ns_list; + enroll_params->encrypted_default_encryption_private_key = + "Ksq6db1VpgDFiT2E39TLyt/NvvRFwlTHLRZIwPZF+RBREODSgqVmLrK5neYNQ+WFQ51h6cYtoSkaAbCpPJH8dAmbVuZGqP5LdrXBbflw0zwaJ+F/" + "qc1eP5uvE60tEko80qeDQoh15tpCny8RwhbWRxCOMaj3+n3AKOFixsz/" + "3Ka4wQxc2zwYTVoiKbrOLnsWdZnV3laEgoP56+Xd891jb3zicw50LICxU9Oj74wR1E+VyzerGTnUH+" + "CXVx7WJ0V5mkGHpac0FsXIC52cmqVQ5sI0AuiyZEV5lg2hefQZSi9Zpu/" + "B5fmxLf7WEbELRjjVUaVoDvOO7fZVFH9MCByXwJeunVzmLGXYm0YngINsA2n4uqPFY+5ku6fmVfWCr+6JLfguKUPIcdVg/OtzdC0Mv/" + "eTjg8YenazHOMPnsfIWK/Ng8aLSX3dyo3ib3BnCbwyYFlgikPv435joYlmAqrkeTYPK8Dg94wG5u/" + "1cSuqmYmKwRSEYcHAQ6Dud2o2t1jCqPhq5s+4FRTbMotUPaGiLITZKJGzDHdJB5nBdhRcjPICvsLEwq10J1lBe/b9qn47Oz3Oq8/" + "pl6ML1ZedW5MCsyjREZJZ/5/" + "oOSdbuWpB9AJNFDHS6KDUXmDWSdmtlrkjNwwmvJmxcpfIO29h+lpmVCg7ot0EYWChdqywnd9YJ+tKuRYCVvBxh+" + "LOAnEZEQiONx53EjSppCxBOyB4ZJzeCyTuGjqYP4SqGvJsCNIL5U2DPLKU2g6dVIFMQHmGzEDW4WcvGbSz62FQOSeD+" + "m5cIdPeejmTAWxl1JSXIWqMBZA6XKNUFh2L/RpYjyXuHURGiyTFv1flwB7/" + "71po1wqPrjMjiaRbRIYKcm1xLcBIvsXqPQDw0FuPYwrhzUkO0hbE+GZlBU8dnzEcP66iccbV3zJcF3mhE3OsBquRSPaqEv/" + "N5yEf8rWbREramAA0oBPwIJUaDv77JyUYaRw5wB2R3rIRgv6l1QhZAbfvaBn9bzsFL1pAoxMKLPS5x20PRHS3KUKJL7oMuAMzeYQZf4XnSWmfe9Y" + "rwTRTL2beRQFqTB8wPS0n3QRWrzeTTQGg5pgVyuW/" + "2pj5zWf8C1Vm2X84rM7hB1+oy2PQxxCQCPxMNWzDkCgHzwefkB+rYhgzP2dGkRqcQUo7JGfEMgNJJ1RfW7/" + "hfr9NGXYnSREH7FTIDdXBOh6pTcG8V+BpAV7f9kknwLTqAGKGsIjw9yGd/M742z1Rpq+VoeVFqXk+aZb3nellRplosO8HQrUWBRfQP2uiqO7ri0/" + "c+0McybH79yDuTyYYbMdmoU77asHsdTxgv1q9PHvcVoijysBtxT+" + "7lD0HZULe7L64V4kyRBjp5qOUiQzkcVK8XkQaCiRIlvlxeIx08FhuU9E70gOpWzyjl4esPGfHx9GWynwvXPhhQ/" + "ws8HbcXMm4rjbFfdkgs3LB6ORACXNqZDhqK1DjzOInH8SBadw4ns7YeT++1WAaPPA/" + "lAmXcZOzrvt2b6pRv6RttkMGJZhQf1PIEA2+GhTJ8ItxGnwlRpceWsuB4RRuroQZNeHD8zqbLDT7Evjcwm3EMoiMm+" + "MtNxP5hUciCZTzrNLKDIOQ00PNxSZW+yYNSHr1fx3SxJaEW4bbqZs2KyF246TOtCwSgbM+dpSrFzTh+/" + "Y6MW5dUWA36bL+HnyHuMSaIWXyj6YCgXe3fLTuEhEUmPYqAxswSkkVtxyn1PFY+L51aXXs0uzWkr00IJ3EB8tpXg4Jku+GfDZ+" + "2wdO7rDy63VHpyG9savIefXSfM8NLmYb6tEw60/" + "FznmO9G90nrXEfzo9KyfbEZ1qvDuy1d7A0GFTSuOLTFvzKzEytVfTayznpd5n3QqeU9V8uVUOwQ2We9sJ2U5ULHxMJ1gKlWpZ2mUB/" + "P3M93PUwTYp4roD147auy+3quhyIyTy3eXwqHYucFeEJ22jINov3JYus8vUWRjuU7/" + "3q3WUTGiz7fEUcr3eaPDMkSOQvUImzXWaOyJCxSC6CHpYMyyQGAW6hn35N5bYO0XyoJxQFhRwsCRa3wi9eQNSE9LizyXeLb980enIzG+" + "P44x3cd8xtpe4ABM3HkiKZAGiJ7Hz0nzs5g5wyd0mLw181nz3RBS/7OvpQ22KzhohHrP6OwzXOnrRvZu62PJ4qe29ODMtecSKYFuMRTJg"; + enroll_params->encrypted_self_encryption_key = "EdHYR+Rol3v1pAigsuSSkOTAkcse3wHXIX9b4tZd7SBrHLXJnZt2EqLur5pIKKjD"; + enroll_params->apkam_public_key = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg1THrbmEpXMDXUtci4GBNaARF2ghWYz6tC5PcO8oyjqioDwlp7lVZcufhgZGD2Dd5" + "j124vyx8t0qlTP/LObK8WvgvLOY5NqUCOgYBv0VufVzOr6xrsNKVEKC9GzMkMbUfFwBVYHeeIg3IKeGTyxB+qHQIAa2gLZCBKX8EsLTGliQmkv2J" + "96umaFTsS/juwxw9nSVpsMIwCcg6hA3njVbjR1p5o9mZ3lVw57GOHzkdyGXXBgKzNvBRXBSDOkNCulxoixrydqWD8sLc8AERQoWCUwSWITTS0YE/" + "jFL8fH2zWupjJ510JmoIf2L2MJsiFFUCtRIRTWSIHs1/cXZiIEvhQIDAQAB"; + + size_t params_json_len = 0; + char *params_json = NULL; + int ret = atcommons_enroll_params_to_json(¶ms_json, ¶ms_json_len, enroll_params); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atcommons_enroll_params_to_json returned: %d\n", ret); + return ret; + } + + ret = atcommons_string_expect(params_json, expected_json); + return ret; +} + +int main() { + int ret = test_case_1(); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "test case 1| ret: %d\n", ret); + return ret; + } + ret = test_case_2(); + if (ret != 0) { + atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "test case 2| ret: %d\n", ret); + return ret; + } + return ret; +} diff --git a/packages/atlogger/src/atlogger.c b/packages/atlogger/src/atlogger.c index cc6ca6a2..a7a803cd 100644 --- a/packages/atlogger/src/atlogger.c +++ b/packages/atlogger/src/atlogger.c @@ -13,9 +13,6 @@ #define ERROR_PREFIX "\e[1;31m[ERROR]\e[0m" #define DEBUG_PREFIX "\e[0;34m[DEBG]\e[0m" -static char prefix[PREFIX_BUFFER_LEN]; -static struct timespec timespec; - typedef struct atlogger_ctx { enum atlogger_logging_level level; int opts; @@ -26,12 +23,10 @@ static int is_ctx_initalized = 0; static atlogger_ctx *atlogger_get_instance() { if (is_ctx_initalized == 0) { - memset(prefix, 0, sizeof(char) * PREFIX_BUFFER_LEN); ctx.opts = ATLOGGER_ENABLE_TIMESTAMPS; is_ctx_initalized = 1; } - return &ctx; } @@ -66,6 +61,7 @@ static void atlogger_get_prefix(enum atlogger_logging_level logging_level, char } atlogger_ctx *ctx = atlogger_get_instance(); + struct timespec timespec; if (ctx->opts & ATLOGGER_ENABLE_TIMESTAMPS) { int res = clock_gettime(CLOCK_REALTIME, ×pec); @@ -77,7 +73,6 @@ static void atlogger_get_prefix(enum atlogger_logging_level logging_level, char res = 0; } } - if (res == 0) { snprintf(prefix + off, PREFIX_BUFFER_LEN - off, ".%09lu", timespec.tv_nsec); off += strlen(prefix + off); @@ -115,9 +110,13 @@ void atlogger_log(const char *tag, const enum atlogger_logging_level level, cons va_list args; va_start(args, format); if (tag != NULL) { - atlogger_get_prefix(level, prefix, PREFIX_BUFFER_LEN); - printf("%.*s ", (int)strlen(prefix), prefix); - printf("%.*s | ", (int)strlen(tag), tag); + char *prefix = malloc(sizeof(char) * PREFIX_BUFFER_LEN); + if (prefix != NULL) { + atlogger_get_prefix(level, prefix, PREFIX_BUFFER_LEN); + printf("%.*s ", (int)strlen(prefix), prefix); + printf("%.*s | ", (int)strlen(tag), tag); + free(prefix); + } } vprintf(format, args); va_end(args); diff --git a/tests/functional_tests/tests/test_atclient_pkam_authenticate.c b/tests/functional_tests/tests/test_atclient_pkam_authenticate.c index a03a57cb..8d4776fd 100644 --- a/tests/functional_tests/tests/test_atclient_pkam_authenticate.c +++ b/tests/functional_tests/tests/test_atclient_pkam_authenticate.c @@ -98,8 +98,8 @@ static int test2_pkam_with_options() { } atlogger_log(tag, ATLOGGER_LOGGING_LEVEL_INFO, "atclient_atkeys_populate_from_atkeys_file: %d\n", ret); - atclient_pkam_authenticate_options options; - atclient_pkam_authenticate_options_init(&options); + atclient_authenticate_options options; + atclient_authenticate_options_init(&options); if ((ret = atclient_utils_find_atserver_address(ATCLIENT_ATDIRECTORY_PRODUCTION_HOST, ATCLIENT_ATDIRECTORY_PRODUCTION_PORT, atsign, &options.atserver_host, diff --git a/tools/run_ctest.sh b/tools/run_ctest.sh index 5b89deb1..d2e57add 100755 --- a/tools/run_ctest.sh +++ b/tools/run_ctest.sh @@ -14,3 +14,4 @@ run_test() { run_test 'packages/atchops/tests' run_test 'packages/atclient/tests' +run_test 'packages/atcommons/tests' \ No newline at end of file