From 22deadaae769b764810652f08dc66552b0090424 Mon Sep 17 00:00:00 2001 From: Nicholas Hemstreet <62158276+nihemstr@users.noreply.github.com> Date: Fri, 17 Nov 2023 21:49:12 -0800 Subject: [PATCH] Integrating the RootKey Feature into the pre-release develop branch (#568) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * initial util and types * remove ECC and change untrusted to disabled * Remove EC conditional from rootkeypackage json schema * build rootkeypackage_utils * Add missing doxygen docs in rootkeypackage_types.h * Fix fn name prefix and add Cleanup * Parse root key package + UTs (#255) * parse bad json pkg * add test for valid protected props * add err code for failed parse of pkg * add parse module, scaffolding * parse version and published * implement most of parsing * add ParseRootKey * revert CMAKE_VERBOSE_MAKEFILE * Complete parsing, add test docs, UTs complete with hardcoded hashs and sigs * add test for verify rootkey rsa params, fix parse rootkey * factor out cleanup into component cleanup functions * Make valgrind clean--fix TestRSAKeyPair memory leak * transfer ownership of kidStrHandle and rsa_modulus only after VECTOR_push_back succeeds * replace all MISSING_REQUIRED_PROPERTY with more specific ERC * rename _Free to _DeInit for RootKey and RootKeyPackage_Hash * rename _Cleanup to _Destroy * replace outlier with ADUC_RootKeyPackage_Hash_DeInit that was supposed to replace it * separate parse of signature and hashes, using RSxxx and SHAversion, respectively * Report DeploymentInPRogress before update manifest signature valid (#256) * Refactor _workflow_parse and create workflow_parse_peek_unprotected_workflow_properties * Report DeploymentInProgress before update manifest signature valid * mv and update rootkeyfiles and add rootkey.json package (#272) * mv and update rootkeyfiles and add rootkey.json package * keytype to keyType and parse number instead of string for 'e' RSA exponent * clang format * Added parsing of the protected properties into a json string for hash… (#274) * Added parsing of the protected properties into a json string for hashing later on * Added granular no mem erc * Implementation of the RootKeyUtility (#279) * parse bad json pkg * add test for valid protected props * add err code for failed parse of pkg * add parse module, scaffolding * parse version and published * implement most of parsing * add ParseRootKey * revert CMAKE_VERBOSE_MAKEFILE * Initial commit * Complete parsing, add test docs, UTs complete with hardcoded hashs and sigs * add test for verify rootkey rsa params, fix parse rootkey * factor out cleanup into component cleanup functions * Make valgrind clean--fix TestRSAKeyPair memory leak * Integrated new work and added stub functions * transfer ownership of kidStrHandle and rsa_modulus only after VECTOR_push_back succeeds * replace all MISSING_REQUIRED_PROPERTY with more specific ERC * Pre-merge commit * Reworking and remerging * Finished implementation and prepared for unit tests * Initial commit for checking into store * Added changes for unit tests * Changing build files and unit tests to reflect latest chagnes * Fixed a few bugs, added some functionality * Added parsing of the protected properties into a json string for hashing later on * Moved to using root key utils root keys * reworked key creation to follow normal flow for checks * reworking names * Unifying result code types and added documentation * updated logs and results * Fixed unit tests, added functionality for RootKeyUtility, and packaged it up nice * Removed musings and miscellaneous comments * responded to feedback and added comments * Responded to more feedback * Fixed init/deinit process for keys Co-authored-by: jw-msft <84477130+jw-msft@users.noreply.github.com> * Add rootkey package download (#275) * Add copyright header to rootkeypackage_parse.c * add GetLastPathSegmentOfUrl in new url_utils * parse rootKeyPackageUrl from propupd json, add call to download fr adu core ifc * impl DO rootkey downloader * add download ut * Add rootkeypackage test app * Move https_proxy_utils into url_utils * Rename to GetPathFileName and rmv dep on libcurl (#285) * Rev deviceUpdate Model and ContractModel to 3 for adu-m rootkey support (#383) * Rev deviceUpdate Model and ContractModel to 3 for adu-m rootkey support * rmv typo, dup word * Added valid tests and fixed bugs exposed by the full unit tests (#395) * Added valid tests and fixed bugs exposed by the full unit tests * Removed unused errors * Add cmake fn to add test root keys only for debug builds (#438) - Add embed_test_root_keys_if_applicable cmake function into new security.cmake - Invoke embed_test_root_keys_if_applicable instead of unconditionally including test root keys - Ran cmake-format.sh - Verified the following using `objdump -s out/src/utils/root_key_utils/CMakeFiles/root_key_utils.dir/src/root_key_lists.c.o`: - `--type=Debug` has 2 retail *and 2 test keys* - `--type=RelWithDebInfo` has only 2 retail keys - `--type=Relelease` has only 2 retail keys - `--type=MinSizeRel` has only 2 retail keys * Added code to create the rootkey store when it does not exist (#448) * Initial integration of rootkeypackage_utils * fix swap of out params when parse unprotected params * pass rootkeypkgurl through to download * Fixed bug where rootkeystore was not created at startup * Repsonded to PR feedback --------- Co-authored-by: jw-msft <84477130+jw-msft@users.noreply.github.com> * report ERCs str, rootkey workflow/dnld fixes, add rootkey telemetry (#489) * report ERCs str, rootkey workflow/dnld fixes, add rootkey telemetry * fix static analysis errors * Add enforcement of disabledSigningKeys rootkey pkg (#495) * Add RootKey disabledSigningKeys support * clang format jws_utils.c * rmv stray commented line * rmv unnecessary malloc+memcpy for CONSTBUFFER_Create * check NULL from GetEvpMdFromShaAlg * add libxml2-dev for codeql github action * Revert "add libxml2-dev for codeql github action" This reverts commit 37215cf11db5eb37ca933178e67e8d129ca9f7d7. * catch exceptions from DO when download rootkey pkg (#528) * catch exceptions from DO when download rootkey pkg * fix cppcheck err for free of possibly uninitialized var * Disabled RootKey/SigningKey Tests and Fix UB crash (#536) * add prod disabled rootkey unit test, no signatures * fix crash rootkey pkg parse not zero after malloc * add test for ReloadPkg and 0 disabled keys * add disabled signingKey GetDisabledSigningKey UT * remove unused fn replaced by CryptoUtils GenPubKey usage * Add isTest support to rootkey pkg schema (#542) * add isTest boolean property to rootkey pkg schema * add isTest to rootkey pkg protected props * fail on mismatch isTest and e2etest agent * include result in report failure * Resolve rootkey download work folder properly after rebase from develop branch. * fix type conv issues found in yocto build * fix another yocto build issue * fix double -> time_t * Adds the ability to create a service e2e compliant test agent (#567) * Creating service side agent e2e build process * Ban strncpy with compilation error, replaced by ADUC_Safe_StrCopyN (#560) * Ban strncpy with compilation error on use * Added changed result code on success * fixed build errors * Integrating OpenSSL 3 Changes and Fixing Pipelines for Ubuntu 22.04 (#544) * Added new sdk update * Changing around apt deployment test to check error * Upgrading to latest C-SDK for OpenSSL integration * Added install instructions for OpenSSL 3.0 in build dependencies * Initial commit with openssl integration * forgot a file * Added support for OpenSSL 3 and added build configs * Adding support for installing non platform standard openssl installations * fixing minor errors * Openssl installation script * Adding additional content for openssl migration * Fixed errors * Adding better #def guards * test * fixing bugs * Adding Ubuntu 22.04 build * pipeline reenabling * removed weird wording * removing enforced openssl requirements * Addressing windows build failures * Removed openssl 1.1.1w installation on ubuntu 22.04 * Corrected the version of Ubuntu 22.04 ARM64 and AMD64 image_offer param * Upgrading the root key modulus work to include openssl 3.0 work * Fixed openssl 3.0 incompatible error * Revert "fixed build errors" This reverts commit 2656c0b1bba7f7e22b810ede1cce800aeca6cbe6. * fixed build errors * Revert "Integrating OpenSSL 3 Changes and Fixing Pipelines for Ubuntu 22.04 (#544)" This reverts commit 5947c463d15ac9788adc785a19af287d2ea8f13e. * fixed double definition * fixed ubuntu 22.04 build errors * format mistake * Added OpenSSL 3.0 version of the CryptoUtils_GeneratePublicKey function and fixed some minor exit function issues * fixing debug issues * fixing debug issues * build error * build. issues. help. --------- Co-authored-by: jw-msft <84477130+jw-msft@users.noreply.github.com> * Ban strncpy with compilation error, replaced by ADUC_Safe_StrCopyN (#560) (#569) * Ban strncpy with compilation error on use Co-authored-by: jw-msft <84477130+jw-msft@users.noreply.github.com> * Fixed merge errors (#572) * Added target_link_dosdk for rootkeypackage * nonsense * Fixed and addressed windows system build errors * fixed errors on linux caused by windows differences * Fixed errors in the root_key_utils get_root_keys function * Fixed test errors * fixed jws utils uts * Added position independent code signifier to prevent bad module integrations --------- Co-authored-by: jw-msft <84477130+jw-msft@users.noreply.github.com> --- .gitignore | 4 + CMakeLists.txt | 28 +- scripts/build.sh | 26 + .../result_codes.json | 2564 ++++++++++------- scripts/install-deps.sh | 2 +- src/CMakeLists.txt | 13 +- src/adu_types/inc/aduc/types/adu_core.h | 1 + src/adu_types/inc/aduc/types/update_content.h | 9 +- src/adu_workflow/CMakeLists.txt | 1 + src/adu_workflow/src/agent_workflow.c | 53 +- src/agent/CMakeLists.txt | 18 +- src/agent/adu_core_interface/CMakeLists.txt | 3 + .../src/adu_core_interface.c | 191 +- .../src/device_properties.c | 2 +- .../src/agent_orchestration.c | 3 +- src/communication_abstraction/CMakeLists.txt | 4 +- .../CMakeLists.txt | 17 +- .../src/iothub_communication_manager.c | 2 +- .../file_info_utils/tests/CMakeLists.txt | 5 + .../utils/file_upload_utils/CMakeLists.txt | 11 +- .../src/microsoft_delta_download_handler.c | 4 +- .../source_update_cache/CMakeLists.txt | 11 +- .../src/extension_manager.cpp | 2 +- .../src/extension_manager_helper.cpp | 8 +- .../extension_manager/tests/CMakeLists.txt | 5 + .../script_handler/CMakeLists.txt | 7 + .../script_handler/tests/CMakeLists.txt | 18 +- .../simulator_handler/CMakeLists.txt | 3 + .../simulator_handler/tests/CMakeLists.txt | 13 +- .../step_handlers/wim_handler/CMakeLists.txt | 7 + .../steps_handler/CMakeLists.txt | 23 +- src/inc/aduc/result.h | 531 +++- src/logging/inc/aduc/logging.h | 5 - src/logging/zlog/inc/zlog.h | 2 - .../linux_platform_layer/tests/CMakeLists.txt | 11 +- src/rootkey_workflow/CMakeLists.txt | 45 + .../inc/aduc/rootkey_workflow.h | 21 + src/rootkey_workflow/src/rootkey_workflow.c | 189 ++ src/rootkey_workflow/tests/CMakeLists.txt | 21 + src/rootkey_workflow/tests/main.cpp | 25 + .../tests/rootkey_workflow_ut.cpp | 28 + src/utils/CMakeLists.txt | 5 +- src/utils/c_utils/inc/aduc/string_c_utils.h | 1 + src/utils/c_utils/src/string_c_utils.c | 40 +- src/utils/crypto_utils/CMakeLists.txt | 14 +- src/utils/crypto_utils/inc/crypto_lib.h | 18 +- src/utils/crypto_utils/src/crypto_lib.c | 530 +++- src/utils/crypto_utils/src/root_key_util.c | 199 -- src/utils/crypto_utils/src/root_key_util.h | 15 - src/utils/crypto_utils/tests/CMakeLists.txt | 8 +- .../crypto_utils/tests/crypto_utils_ut.cpp | 39 +- src/utils/entity_utils/CMakeLists.txt | 4 +- src/utils/hash_utils/CMakeLists.txt | 2 +- src/utils/hash_utils/inc/aduc/hash_utils.h | 8 + src/utils/hash_utils/src/hash_utils.c | 4 +- .../https_proxy_utils/tests/CMakeLists.txt | 22 - .../tests/CMakeLists.txt | 5 + src/utils/jws_utils/CMakeLists.txt | 2 +- src/utils/jws_utils/inc/jws_utils.h | 25 +- src/utils/jws_utils/src/jws_utils.c | 217 +- src/utils/jws_utils/tests/CMakeLists.txt | 10 +- src/utils/jws_utils/tests/jws_utils_ut.cpp | 182 +- .../testdata/jws_utils/testrootkeypkg.json | 1 + src/utils/process_utils/src/process_utils.cpp | 4 - .../CMakeLists.txt | 14 +- .../inc/aduc/reporting_utils.h | 17 + .../reporting_utils/src/reporting_utils.c | 57 + .../reporting_utils/tests/CMakeLists.txt | 18 + src/utils/reporting_utils/tests/main.cpp | 9 + .../tests/reporting_utils_ut.cpp | 94 + src/utils/retry_utils/CMakeLists.txt | 7 +- src/utils/root_key_utils/CMakeLists.txt | 34 + src/utils/root_key_utils/inc/root_key_list.h | 29 + src/utils/root_key_utils/inc/root_key_store.h | 19 + src/utils/root_key_utils/inc/root_key_util.h | 36 + src/utils/root_key_utils/src/root_key_list.c | 103 + src/utils/root_key_utils/src/root_key_store.c | 27 + src/utils/root_key_utils/src/root_key_util.c | 886 ++++++ src/utils/root_key_utils/tests/CMakeLists.txt | 27 + src/utils/root_key_utils/tests/main.cpp | 40 + .../tests/root_key_utils_signing_key_ut.cpp | 88 + .../tests/root_key_utils_ut.cpp | 388 +++ .../root_key_utils/disabledRootKeyProd.json | 30 + .../disabledSigningKeyProd.json | 33 + .../root_key_utils/invalidrootkeypackage.json | 30 + .../root_key_utils/validrootkeypackage.json | 30 + src/utils/rootkeypackage_utils/CMakeLists.txt | 34 + .../inc/aduc/rootkeypackage.schema.json | 111 + .../inc/aduc/rootkeypackage_do_download.h | 22 + .../inc/aduc/rootkeypackage_download.h | 29 + .../inc/aduc/rootkeypackage_json_properties.h | 27 + .../inc/aduc/rootkeypackage_parse.h | 41 + .../inc/aduc/rootkeypackage_types.h | 100 + .../inc/aduc/rootkeypackage_utils.h | 38 + .../src/rootkeypackage_do_download.cpp | 53 + .../src/rootkeypackage_download.c | 134 + .../src/rootkeypackage_parse.c | 991 +++++++ .../src/rootkeypackage_utils.c | 681 +++++ .../rootkeypackage_utils/tests/CMakeLists.txt | 35 + .../tests/inc/rootkeypkgtestutils.hpp | 361 +++ .../scripts/rootkeypkg/rootkeyfiles/README.md | 29 + .../create_and_verify_signatures.sh | 23 + .../rootkeyfiles/modulus_1.base64url.txt | 1 + .../rootkeyfiles/modulus_2.base64url.txt | 1 + .../rootkeyfiles/root2.sig.base64.txt | 6 + .../rootkeypkg/rootkeyfiles/rootkey.data.json | 1 + .../rootkeypkg/rootkeyfiles/rootkey.json | 38 + .../rootkeyfiles/testroot1.base64.txt | 35 + .../rootkeypkg/rootkeyfiles/testroot1.txt | 25 + .../rootkeyfiles/testroot2.base64.txt | 35 + .../rootkeypkg/rootkeyfiles/testroot2.txt | 25 + .../rootkeypackage_utils/tests/src/main.cpp | 9 + .../tests/src/rootkeypackage_download_ut.cpp | 95 + .../tests/src/rootkeypackage_utils_ut.cpp | 390 +++ .../tests/testapp/CMakeLists.txt | 12 + .../tests/testapp/README.md | 23 + .../tests/testapp/src/main.cpp | 69 + .../rootkeypackage_utils/rootkeypackage.json | 38 + .../rootkeypackage_template.json | 45 + .../system_utils/inc/aduc/system_utils.h | 2 + src/utils/system_utils/src/system_utils.c | 40 +- .../test_utils/inc/aduc/file_test_utils.hpp | 3 + src/utils/test_utils/src/file_test_utils.cpp | 10 + src/utils/url_utils/CMakeLists.txt | 17 + .../inc/aduc/https_proxy_utils.h | 0 src/utils/url_utils/inc/aduc/url_utils.h | 22 + .../src/https_proxy_utils.c | 0 src/utils/url_utils/src/url_utils.c | 99 + src/utils/url_utils/tests/CMakeLists.txt | 20 + .../tests/https_proxy_utils_ut.cpp | 0 .../tests/main.cpp | 2 +- src/utils/url_utils/tests/url_utils_ut.cpp | 68 + .../inc/aduc/workflow_data_utils.h | 7 + .../src/workflow_data_utils.c | 12 + src/utils/workflow_utils/CMakeLists.txt | 5 +- .../inc/aduc/workflow_internal.h | 3 +- .../workflow_utils/inc/aduc/workflow_utils.h | 39 +- src/utils/workflow_utils/src/workflow_utils.c | 753 +++-- src/utils/workflow_utils/tests/CMakeLists.txt | 9 +- .../tests/workflow_get_update_file_ut.cpp | 13 +- .../tests/workflow_utils_ut.cpp | 98 +- 141 files changed, 10239 insertions(+), 1847 deletions(-) create mode 100644 src/rootkey_workflow/CMakeLists.txt create mode 100644 src/rootkey_workflow/inc/aduc/rootkey_workflow.h create mode 100644 src/rootkey_workflow/src/rootkey_workflow.c create mode 100644 src/rootkey_workflow/tests/CMakeLists.txt create mode 100644 src/rootkey_workflow/tests/main.cpp create mode 100644 src/rootkey_workflow/tests/rootkey_workflow_ut.cpp delete mode 100644 src/utils/crypto_utils/src/root_key_util.c delete mode 100644 src/utils/crypto_utils/src/root_key_util.h delete mode 100644 src/utils/https_proxy_utils/tests/CMakeLists.txt create mode 100644 src/utils/jws_utils/tests/testdata/jws_utils/testrootkeypkg.json rename src/utils/{https_proxy_utils => reporting_utils}/CMakeLists.txt (53%) create mode 100644 src/utils/reporting_utils/inc/aduc/reporting_utils.h create mode 100644 src/utils/reporting_utils/src/reporting_utils.c create mode 100644 src/utils/reporting_utils/tests/CMakeLists.txt create mode 100644 src/utils/reporting_utils/tests/main.cpp create mode 100644 src/utils/reporting_utils/tests/reporting_utils_ut.cpp create mode 100644 src/utils/root_key_utils/CMakeLists.txt create mode 100644 src/utils/root_key_utils/inc/root_key_list.h create mode 100644 src/utils/root_key_utils/inc/root_key_store.h create mode 100644 src/utils/root_key_utils/inc/root_key_util.h create mode 100644 src/utils/root_key_utils/src/root_key_list.c create mode 100644 src/utils/root_key_utils/src/root_key_store.c create mode 100644 src/utils/root_key_utils/src/root_key_util.c create mode 100644 src/utils/root_key_utils/tests/CMakeLists.txt create mode 100644 src/utils/root_key_utils/tests/main.cpp create mode 100644 src/utils/root_key_utils/tests/root_key_utils_signing_key_ut.cpp create mode 100644 src/utils/root_key_utils/tests/root_key_utils_ut.cpp create mode 100644 src/utils/root_key_utils/tests/testdata/root_key_utils/disabledRootKeyProd.json create mode 100644 src/utils/root_key_utils/tests/testdata/root_key_utils/disabledSigningKeyProd.json create mode 100644 src/utils/root_key_utils/tests/testdata/root_key_utils/invalidrootkeypackage.json create mode 100644 src/utils/root_key_utils/tests/testdata/root_key_utils/validrootkeypackage.json create mode 100644 src/utils/rootkeypackage_utils/CMakeLists.txt create mode 100644 src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage.schema.json create mode 100644 src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_do_download.h create mode 100644 src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_download.h create mode 100644 src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_json_properties.h create mode 100644 src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_parse.h create mode 100644 src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_types.h create mode 100644 src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_utils.h create mode 100644 src/utils/rootkeypackage_utils/src/rootkeypackage_do_download.cpp create mode 100644 src/utils/rootkeypackage_utils/src/rootkeypackage_download.c create mode 100644 src/utils/rootkeypackage_utils/src/rootkeypackage_parse.c create mode 100644 src/utils/rootkeypackage_utils/src/rootkeypackage_utils.c create mode 100644 src/utils/rootkeypackage_utils/tests/CMakeLists.txt create mode 100644 src/utils/rootkeypackage_utils/tests/inc/rootkeypkgtestutils.hpp create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/README.md create mode 100755 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/create_and_verify_signatures.sh create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_1.base64url.txt create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_2.base64url.txt create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/root2.sig.base64.txt create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.data.json create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.json create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.base64.txt create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.txt create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.base64.txt create mode 100644 src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.txt create mode 100644 src/utils/rootkeypackage_utils/tests/src/main.cpp create mode 100644 src/utils/rootkeypackage_utils/tests/src/rootkeypackage_download_ut.cpp create mode 100644 src/utils/rootkeypackage_utils/tests/src/rootkeypackage_utils_ut.cpp create mode 100644 src/utils/rootkeypackage_utils/tests/testapp/CMakeLists.txt create mode 100644 src/utils/rootkeypackage_utils/tests/testapp/README.md create mode 100644 src/utils/rootkeypackage_utils/tests/testapp/src/main.cpp create mode 100644 src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage.json create mode 100644 src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage_template.json create mode 100644 src/utils/url_utils/CMakeLists.txt rename src/utils/{https_proxy_utils => url_utils}/inc/aduc/https_proxy_utils.h (100%) create mode 100644 src/utils/url_utils/inc/aduc/url_utils.h rename src/utils/{https_proxy_utils => url_utils}/src/https_proxy_utils.c (100%) create mode 100644 src/utils/url_utils/src/url_utils.c create mode 100644 src/utils/url_utils/tests/CMakeLists.txt rename src/utils/{https_proxy_utils => url_utils}/tests/https_proxy_utils_ut.cpp (100%) rename src/utils/{https_proxy_utils => url_utils}/tests/main.cpp (79%) create mode 100644 src/utils/url_utils/tests/url_utils_ut.cpp diff --git a/.gitignore b/.gitignore index cc5e503c7..b1aaf78af 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,10 @@ cscope.out cscope.in.out cscope.po.out +### openssl output +*.sig +*.pem + ### Python Module Files *__pycache__ *__pycache__/* diff --git a/CMakeLists.txt b/CMakeLists.txt index e5fcb6380..144b50ede 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,23 +212,36 @@ else () ADUC_STEP_HANDLERS "microsoft/swupdate_v2,microsoft/swupdate,microsoft/script,microsoft/apt,microsoft/simulator" CACHE STRING "The list of step handlers.") - - set ( - ADUC_STEP_HANDLERS - "microsoft/swupdate_v2,microsoft/swupdate,microsoft/script,microsoft/apt,microsoft/simulator" - CACHE STRING "The list of step handlers.") endif () +set ( + ADUC_ROOTKEY_STORE_PATH + "${ADUC_DATA_FOLDER}/rootkeystore/" + CACHE STRING "Path to the folder containing the information for the local store of root keys") + +set ( + ADUC_ROOTKEY_STORE_PACKAGE_PATH + "${ADUC_ROOTKEY_STORE_PATH}/rootkeys.json" + CACHE STRING "Path to the folder containing the local root keys") + set ( ADUC_COMMANDS_FIFO_NAME "${ADUC_DATA_FOLDER}/du-commands.fifo" CACHE STRING "The named-pipe for commands IPC.") +set ( + ADUC_ROOTKEY_PKG_URL_OVERRIDE + "" + CACHE + STRING + "An override URL to use for the public rootkey package. Leave empty to use the URL provided in the C2D message." +) + # # Starting from version 0.8.1, Device Update Agent must support only one version of the update manifest # based on the base dtmi model that the Agent announces when connecting to the IoT Hub. # -# For this version, "dtmi:azure:iot:deviceUpdateModel;2" is using the manifest version verison 5. +# For this version, "dtmi:azure:iot:deviceUpdateModel;3" is using the manifest version 5. # set (SUPPORTED_UPDATE_MANIFEST_VERSION_MIN 4) set (SUPPORTED_UPDATE_MANIFEST_VERSION_MAX 5) @@ -464,6 +477,9 @@ option (ADUC_BUILD_PACKAGES "Build the ADU Agent packages" OFF) option (ADUC_INSTALL_DAEMON "Install the ADU Agent as a daemon" ON) option (ADUC_REGISTER_DAEMON "Register the ADU Agent daemon with the system" ON) option (ADUC_TRACE_TARGET_DEPS "Trace target dependencies" OFF) +option (ADUC_USE_TEST_ROOT_KEYS "Include test root keys" OFF) +option (ADUC_ENABLE_E2E_TESTING "Enable e2e test pipeline settings" OFF) +option (ADUC_ENABLE_SRVC_E2E_TESTING "Enable service side test agent settings" OFF) ### End CMake Options diff --git a/scripts/build.sh b/scripts/build.sh index ae118018d..a902cbdea 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -31,11 +31,14 @@ build_packages=false platform_layer="linux" trace_target_deps=false step_handlers="microsoft/apt,microsoft/script,microsoft/simulator,microsoft/swupdate,microsoft/swupdate_v2" +use_test_root_keys=false +srvc_e2e_agent_build=false build_type=Debug adu_log_dir="" default_log_dir=/var/log/adu output_directory=$root_dir/out build_unittests=false +enable_e2e_testing=false declare -a static_analysis_tools=() log_lib="zlog" install_prefix=/usr/local @@ -50,6 +53,7 @@ print_help() { echo " Options: Release Debug RelWithDebInfo MinSizeRel" echo "-d, --build-docs Builds the documentation." echo "-u, --build-unit-tests Builds unit tests." + echo "--enable-e2e-testing Enables settings for the E2E test pipelines." echo "--build-packages Builds and packages the client in various package formats e.g debian." echo "-o, --out-dir Sets the build output directory. Default is out." echo "-s, --static-analysis Runs static analysis as part of the build." @@ -225,6 +229,9 @@ while [[ $1 != "" ]]; do -u | --build-unit-tests) build_unittests=true ;; + --enable-e2e-testing) + enable_e2e_testing=true + ;; --build-packages) build_packages=true ;; @@ -262,6 +269,12 @@ while [[ $1 != "" ]]; do --trace-target-deps) trace_target_deps=true ;; + --use-test-root-keys) + use_test_root_keys=true + ;; + --build-service-e2e-agent) + srvc_e2e_agent_build=true + ;; --log-lib) shift if [[ -z $1 || $1 == -* ]]; then @@ -347,6 +360,15 @@ library_dir=${output_directory}/lib cmake_bin="${cmake_dir_path}/bin/cmake" shellcheck_bin="${work_folder}/deviceupdate-shellcheck" +if [[ $srvc_e2e_agent_build == "true" ]]; then + warn "BUILDING SERVICE E2E AGENT NEVER USE FOR PRODUCTION" + echo "Additionally implies: " + echo " --enable-e2e-testing , --use-test-root-keys, --build-packages" + use_test_root_keys=true + enable_e2e_testing=true + build_packages=true +fi + # Output banner echo '' header "Building ADU Agent" @@ -360,6 +382,7 @@ bullet "Log directory: $adu_log_dir" bullet "Logging library: $log_lib" bullet "Output directory: $output_directory" bullet "Build unit tests: $build_unittests" +bullet "Enable E2E testing: $enable_e2e_testing" bullet "Build packages: $build_packages" bullet "CMake: $cmake_bin" bullet "CMake version: $(${cmake_bin} --version | grep version | awk '{ print $3 }')" @@ -370,6 +393,7 @@ if [[ ${#static_analysis_tools[@]} -eq 0 ]]; then else bullet "Static analysis: " "${static_analysis_tools[@]}" fi +bullet "Include Test Root Keys: $use_test_root_keys" echo '' CMAKE_OPTIONS=( @@ -377,10 +401,12 @@ CMAKE_OPTIONS=( "-DADUC_BUILD_UNIT_TESTS:BOOL=$build_unittests" "-DADUC_BUILD_PACKAGES:BOOL=$build_packages" "-DADUC_STEP_HANDLERS:STRING=$step_handlers" + "-DADUC_ENABLE_E2E_TESTING=$enable_e2e_testing" "-DADUC_LOG_FOLDER:STRING=$adu_log_dir" "-DADUC_LOGGING_LIBRARY:STRING=$log_lib" "-DADUC_PLATFORM_LAYER:STRING=$platform_layer" "-DADUC_TRACE_TARGET_DEPS=$trace_target_deps" + "-DADUC_USE_TEST_ROOT_KEYS=$use_test_root_keys" "-DCMAKE_BUILD_TYPE:STRING=$build_type" "-DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON" "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY:STRING=$library_dir" diff --git a/scripts/error_code_generator_defs/result_codes.json b/scripts/error_code_generator_defs/result_codes.json index de30eeeb3..6fc707cfa 100644 --- a/scripts/error_code_generator_defs/result_codes.json +++ b/scripts/error_code_generator_defs/result_codes.json @@ -1,1124 +1,1464 @@ { "facilities": [ - { - "components": [ - { + { + "components": [ + { + "code": 0, + "doc_string": "General Error Codes, that come from POSIX 2001 Standard Errnos", + "name": "ERRNO", + "results": [ + { + "name": "ADUC_ERC_NOTPERMITTED", + "value": 1 + }, + { + "name": "ADUC_ERC_NOMEM", + "value": 12 + }, + { + "name": "ADUC_ERC_INVAL", + "value": 22 + }, + { + "name": "ADUC_ERC_NOTRECOVERABLE", + "value": 131 + } + ] + }, + { + "code": 1, + "doc_string": "validation and cryptographic component", + "name": "ADUC_COMPONENT_CRYPTO", + "results": [ + { + "name": "ADUC_ERC_VALIDATION_FILE_HASH_IS_EMPTY", + "value": 1 + }, + { + "name": "ADUC_ERC_VALIDATION_FILE_HASH_TYPE_NOT_SUPPORTED", + "value": 2 + }, + { + "name": "ADUC_ERC_VALIDATION_FILE_HASH_INVALID_HASH", + "value": 3 + } + ] + }, + { + "code": 2, + "doc_string": "plugin call helper component", + "name": "ADUC_COMPONENT_PLUGIN_CALL", + "results": [ + { + "name": "ADUC_ERC_PLUGIN_CALL_RESOLVE_EXPORT_SYMBOL", + "value": 1 + } + ] + }, + { + "code": 3, + "doc_string": "Errors that are common across the codebase but are not ERRNO errors", + "name": "ADUC_COMPONENT_COMMON_ERRORS", + "results": [ + { + "name": "ADUC_ERC_INVALIDARG", + "value": 1 + } + ] + } + ], "code": 0, - "doc_string": "General Error Codes, that come from POSIX 2001 Standard Errnos", - "name": "ERRNO", - "results": [ - { - "name": "ADUC_ERC_NOTPERMITTED", - "value": 1 - }, - { - "name": "ADUC_ERC_NOMEM", - "value": 12 - }, - { - "name": "ADUC_ERC_NOTRECOVERABLE", - "value": 131 - } - ] - }, - { + "doc_string": "indicates errors from unknown sources", + "name": "ADUC_FACILITY_UNKNOWN" + }, + { + "components": [ + { + "code": 0, + "doc_string": "non component specific error codes", + "name": "ADUC_LOWERLAYER_COMMON", + "results": [ + { + "name": "ADUC_ERC_LOWERLEVEL_INVALID_UPDATE_ACTION", + "value": 1 + }, + { + "name": "ADUC_ERC_LOWERLEVEL_UPDATE_MANIFEST_VALIDATION_INVALID_HASH", + "value": 2 + }, + { + "name": "ADUC_ERC_LOWERLEVEL_GET_FILE_ENTITY_FAILURE", + "value": 3 + }, + { + "name": "ADUC_ERC_LOWERLEVEL_SANDBOX_CREATE_FAILURE_NO_ADU_USER", + "value": 5 + }, + { + "name": "ADUC_ERC_LOWERLEVEL_SANDBOX_CREATE_FAILURE_NO_ADU_GROUP", + "value": 6 + }, + { + "name": "ADUC_ERC_LOWERLEVEL_WORKFLOW_INIT_ERROR_NULL_PARAM", + "value": 20 + } + ] + } + ], "code": 1, - "doc_string": "validation and cryptographic component", - "name": "ADUC_COMPONENT_CRYPTO", - "results": [ - { - "name": "ADUC_ERC_VALIDATION_FILE_HASH_IS_EMPTY", - "value": 1 - }, - { - "name": "ADUC_ERC_VALIDATION_FILE_HASH_TYPE_NOT_SUPPORTED", - "value": 2 - }, - { - "name": "ADUC_ERC_VALIDATION_FILE_HASH_INVALID_HASH", - "value": 3 - } - ] - }, - { + "doc_string": "indicates errors from the lower layer", + "name": "ADUC_FACILITY_LOWERLAYER" + }, + { + "components": [ + { + "code": 0, + "doc_string": "non component specific error codes", + "name": "ADUC_UPPERLAYER_COMMON", + "results": [ + { + "name": "ADUC_ERC_UPPERLEVEL_WORKFLOW_UPDATE_ACTION_UNEXPECTED_STATE", + "value": 1 + }, + { + "name": "ADUC_ERC_UPPERLEVEL_WORKFLOW_INSTALL_ACTION_IN_UNEXPECTED_STATE", + "value": 2 + }, + { + "name": "ADUC_ERC_UPPERLEVEL_WORKFLOW_FAILED_RESTORE_FAILED", + "value": 3 + } + ] + } + ], "code": 2, - "doc_string": "plugin call helper component", - "name": "ADUC_COMPONENT_PLUGIN_CALL", - "results": [ - { - "name": "ADUC_ERC_PLUGIN_CALL_RESOLVE_EXPORT_SYMBOL", - "value": 1 - } - ] - } - ], - "code": 0, - "doc_string": "indicates errors from unknown sources", - "name": "ADUC_FACILITY_UNKNOWN" - }, - { - "components": [ - { - "code": 0, - "doc_string": "non component specific error codes", - "name": "ADUC_LOWERLAYER_COMMON", - "results": [ - { - "name": "ADUC_ERC_LOWERLEVEL_INVALID_UPDATE_ACTION", - "value": 1 - }, - { - "name": "ADUC_ERC_LOWERLEVEL_UPDATE_MANIFEST_VALIDATION_INVALID_HASH", - "value": 2 - }, - { - "name": "ADUC_ERC_LOWERLEVEL_GET_FILE_ENTITY_FAILURE", - "value": 3 - }, - { - "name": "ADUC_ERC_LOWERLEVEL_SANDBOX_CREATE_FAILURE_NO_ADU_USER", - "value": 5 - }, - { - "name": "ADUC_ERC_LOWERLEVEL_SANDBOX_CREATE_FAILURE_NO_ADU_GROUP", - "value": 6 - }, - { - "name": "ADUC_ERC_LOWERLEVEL_WORKFLOW_INIT_ERROR_NULL_PARAM", - "value": 20 - } - ] - } - ], - "code": 1, - "doc_string": "indicates errors from the lower layer", - "name": "ADUC_FACILITY_LOWERLAYER" - }, - { - "components": [ - { - "code": 0, - "doc_string": "non component specific error codes", - "name": "ADUC_UPPERLAYER_COMMON", - "results": [ - { - "name": "ADUC_ERC_UPPERLEVEL_WORKFLOW_UPDATE_ACTION_UNEXPECTED_STATE", - "value": 1 - }, - { - "name": "ADUC_ERC_UPPERLEVEL_WORKFLOW_INSTALL_ACTION_IN_UNEXPECTED_STATE", - "value": 2 - }, - { - "name": "ADUC_ERC_UPPERLEVEL_WORKFLOW_FAILED_RESTORE_FAILED", - "value": 3 - } - ] - } - ], - "code": 2, - "doc_string": "indicates errors from the upper layer.", - "name": "ADUC_FACILITY_UPPERLAYER" - }, - { - "components": [ - { - "code": 0, - "doc_string": "General error codes that can come from any step handler", - "name": "ADUC_CONTENT_HANDLER_COMMON", - "results": [ - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_INVALID_ARG", - "value": 1 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_UNKNOWN", - "value": 2 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_NOT_FOUND", - "value": 3 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_VALIDATE", - "value": 4 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_LOAD", - "value": 5 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_NO_SYMBOL", - "value": 6 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_CREATE", - "value": 7 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_PREPARE_FAILURE_WRONG_VERSION", - "value": 101 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_PARSE_BAD_FORMAT", - "value": 104 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_DOWNLOAD_FAILURE_BADFILECOUNT", - "value": 201 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_DOWNLOAD_FAILURE_UNKNOWNEXCEPTION", - "value": 202 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_NULL_WORKFLOW", - "value": 301 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_MISSING_PRIMARY_FILE", - "value": 302 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_MISSING_PRIMARY_COMPONENT", - "value": 303 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_UNKNOWNEXCEPTION", - "value": 304 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_BAD_UPDATETYPE", - "value": 501 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_COMPONENT_UNAVAILABLE", - "value": 502 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_NULL_WORKFLOW", - "value": 503 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_NULL_WORKFLOW_HANDLE", - "value": 504 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_NO_STEPS", - "value": 505 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_ACCESS_DATA", - "value": 506 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_GET_CONTRACT_INFO_CALL_FAILURE", - "value": 507 - }, - { - "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_UNSUPPORTED_CONTRACT_VERSION", - "value": 508 - } - ] - }, - { - "code": 1, - "doc_string": "Results that originate from the SwUpdate Step Handler", - "name": "ADUC_CONTENT_HANDLER_SWUPDATE", - "results": [ - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_EMPTY_VERSION", - "value": 1 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_UNKNOWN_UPDATE_VERSION", - "value": 2 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_WRONG_UPDATE_VERSION", - "value": 3 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_WRONG_FILECOUNT", - "value": 4 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_BAD_FILE_ENTITY", - "value": 5 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_CREATE_SANDBOX_FAILURE", - "value": 6 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_MISSING_SCRIPT_FILE_NAME", - "value": 7 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_MISSING_SWU_FILE_NAME", - "value": 8 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_TOO_MANY_COMPONENTS", - "value": 9 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INVALID_COMPONENTS_DATA", - "value": 10 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_BAD_SWUPDATE_CONFIG_FILE", - "value": 32 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_PERFORM_ACTION_FAILED_TO_GET_CONFIG_INSTANCE", - "value": 33 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_UNKNOWN_UPDATE_VERSION", - "value": 257 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_WRONG_UPDATE_VERSION", - "value": 258 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_WRONG_FILECOUNT", - "value": 259 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_BAD_FILE_ENTITY", - "value": 260 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_ERROR_NULL_WORKFLOW", - "value": 261 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_GET_PRIMARY_FILE_ENTITY", - "value": 262 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_GET_SCRIPT_FILE_ENTITY", - "value": 263 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_GET_PAYLOAD_FILE_ENTITY", - "value": 264 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_PAYLOAD_FILE_FAILURE_UNKNOWNEXCEPTION", - "value": 510 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_PRIMARY_FILE_FAILURE_UNKNOWNEXCEPTION", - "value": 511 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_CANNOT_OPEN_WORKFOLDER", - "value": 513 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_IMAGE_FILE_NOT_FOUND", - "value": 514 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_ERROR_NULL_WORKFLOW", - "value": 515 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_BAD_FILE_ENTITY", - "value": 516 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_PARSE_RESULT_FILE", - "value": 517 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_MISSING_INSTALLED_CRITERIA", - "value": 518 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILED_TO_GET_CONFIG_INSTANCE", - "value": 519 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_UNKNOWNEXCEPTION", - "value": 767 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_APPLY_FAILURE", - "value": 768 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_APPLY_FAILED_TO_GET_CONFIG_INSTANCE", - "value": 769 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_CANCEL_FAILURE", - "value": 1024 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_CANCEL_FAILED_TO_GET_CONFIG_INSTANCE", - "value": 1025 - }, - { - "name": "ADUC_ERC_SWUPDATE_HANDLER_CANCEL_FAILED_TO_CANCEL_APPLIED_UPDATE", - "value": 1026 - } - ] - }, - { - "code": 2, - "doc_string": "Results that originate from the APT Step Handler", - "name": "ADUC_CONTENT_HANDLER_APT", - "results": [ - { - "name": "ADUC_ERC_APT_HANDLER_ERROR_NONE", - "value": 0 - }, - { - "name": "ADUC_ERC_APT_HANDLER_INITIALIZATION_FAILURE", - "value": 1 - }, - { - "name": "ADUC_ERC_APT_HANDLER_INVALID_PACKAGE_DATA", - "value": 2 - }, - { - "name": "ADUC_ERC_APT_HANDLER_PACKAGE_PREPARE_FAILURE_WRONG_VERSION", - "value": 3 - }, - { - "name": "ADUC_ERC_APT_HANDLER_PACKAGE_PREPARE_FAILURE_WRONG_FILECOUNT", - "value": 4 - }, - { - "name": "ADUC_ERC_APT_HANDLER_GET_FILEENTITY_FAILURE", - "value": 5 - }, - { - "name": "ADUC_ERC_APT_HANDLER_INSTALLCRITERIA_PERSIST_FAILURE", - "value": 6 - }, - { - "name": "ADUC_ERC_APT_HANDLER_MISSING_INSTALLED_CRITERIA", - "value": 7 - }, - { - "name": "ADUC_ERC_APT_HANDLER_PACKAGE_DOWNLOAD_FAILURE", - "value": 256 - }, - { - "name": "ADUC_ERC_APT_HANDLER_DOWNLOAD_FAILED_TO_GET_CONFIG_INSTANCE", - "value": 257 - }, - { - "name": "ADUC_ERC_APT_HANDLER_PACKAGE_INSTALL_FAILURE", - "value": 512 - }, - { - "name": "ADUC_ERC_APT_HANDLER_INSTALL_FAILED_TO_GET_CONFIG_INSTANCE", - "value": 513 - }, - { - "name": "ADUC_ERC_APT_HANDLER_PACKAGE_CANCEL_FAILURE", - "value": 1024 - } - ] - }, - { + "doc_string": "indicates errors from the upper layer.", + "name": "ADUC_FACILITY_UPPERLAYER" + }, + { + "components": [ + { + "code": 0, + "doc_string": "General error codes that can come from any step handler", + "name": "ADUC_CONTENT_HANDLER_COMMON", + "results": [ + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_INVALID_ARG", + "value": 1 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_UNKNOWN", + "value": 2 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_NOT_FOUND", + "value": 3 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_VALIDATE", + "value": 4 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_LOAD", + "value": 5 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_NO_SYMBOL", + "value": 6 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_CREATE_FAILURE_CREATE", + "value": 7 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_PREPARE_FAILURE_WRONG_VERSION", + "value": 101 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_PARSE_BAD_FORMAT", + "value": 104 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_DOWNLOAD_FAILURE_BADFILECOUNT", + "value": 201 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_DOWNLOAD_FAILURE_UNKNOWNEXCEPTION", + "value": 202 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_NULL_WORKFLOW", + "value": 301 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_MISSING_PRIMARY_FILE", + "value": 302 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_MISSING_PRIMARY_COMPONENT", + "value": 303 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_INSTALL_FAILURE_UNKNOWNEXCEPTION", + "value": 304 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_BAD_UPDATETYPE", + "value": 501 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_COMPONENT_UNAVAILABLE", + "value": 502 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_NULL_WORKFLOW", + "value": 503 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_NULL_WORKFLOW_HANDLE", + "value": 504 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_NO_STEPS", + "value": 505 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_ISINSTALLED_FAILURE_ACCESS_DATA", + "value": 506 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_GET_CONTRACT_INFO_CALL_FAILURE", + "value": 507 + }, + { + "name": "ADUC_ERC_UPDATE_CONTENT_HANDLER_UNSUPPORTED_CONTRACT_VERSION", + "value": 508 + } + ] + }, + { + "code": 1, + "doc_string": "Results that originate from the SwUpdate Step Handler", + "name": "ADUC_CONTENT_HANDLER_SWUPDATE", + "results": [ + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_EMPTY_VERSION", + "value": 1 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_UNKNOWN_UPDATE_VERSION", + "value": 2 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_WRONG_UPDATE_VERSION", + "value": 3 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_WRONG_FILECOUNT", + "value": 4 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_PREPARE_FAILURE_BAD_FILE_ENTITY", + "value": 5 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_CREATE_SANDBOX_FAILURE", + "value": 6 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_MISSING_SCRIPT_FILE_NAME", + "value": 7 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_MISSING_SWU_FILE_NAME", + "value": 8 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_TOO_MANY_COMPONENTS", + "value": 9 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INVALID_COMPONENTS_DATA", + "value": 10 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_BAD_SWUPDATE_CONFIG_FILE", + "value": 32 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_PERFORM_ACTION_FAILED_TO_GET_CONFIG_INSTANCE", + "value": 33 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_UNKNOWN_UPDATE_VERSION", + "value": 257 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_WRONG_UPDATE_VERSION", + "value": 258 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_WRONG_FILECOUNT", + "value": 259 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_BAD_FILE_ENTITY", + "value": 260 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_ERROR_NULL_WORKFLOW", + "value": 261 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_GET_PRIMARY_FILE_ENTITY", + "value": 262 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_GET_SCRIPT_FILE_ENTITY", + "value": 263 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_GET_PAYLOAD_FILE_ENTITY", + "value": 264 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_PAYLOAD_FILE_FAILURE_UNKNOWNEXCEPTION", + "value": 510 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_PRIMARY_FILE_FAILURE_UNKNOWNEXCEPTION", + "value": 511 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_CANNOT_OPEN_WORKFOLDER", + "value": 513 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_IMAGE_FILE_NOT_FOUND", + "value": 514 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_ERROR_NULL_WORKFLOW", + "value": 515 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_BAD_FILE_ENTITY", + "value": 516 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_PARSE_RESULT_FILE", + "value": 517 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_MISSING_INSTALLED_CRITERIA", + "value": 518 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILED_TO_GET_CONFIG_INSTANCE", + "value": 519 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_UNKNOWNEXCEPTION", + "value": 767 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_APPLY_FAILURE", + "value": 768 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_APPLY_FAILED_TO_GET_CONFIG_INSTANCE", + "value": 769 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_CANCEL_FAILURE", + "value": 1024 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_CANCEL_FAILED_TO_GET_CONFIG_INSTANCE", + "value": 1025 + }, + { + "name": "ADUC_ERC_SWUPDATE_HANDLER_CANCEL_FAILED_TO_CANCEL_APPLIED_UPDATE", + "value": 1026 + } + ] + }, + { + "code": 2, + "doc_string": "Results that originate from the APT Step Handler", + "name": "ADUC_CONTENT_HANDLER_APT", + "results": [ + { + "name": "ADUC_ERC_APT_HANDLER_ERROR_NONE", + "value": 0 + }, + { + "name": "ADUC_ERC_APT_HANDLER_INITIALIZATION_FAILURE", + "value": 1 + }, + { + "name": "ADUC_ERC_APT_HANDLER_INVALID_PACKAGE_DATA", + "value": 2 + }, + { + "name": "ADUC_ERC_APT_HANDLER_PACKAGE_PREPARE_FAILURE_WRONG_VERSION", + "value": 3 + }, + { + "name": "ADUC_ERC_APT_HANDLER_PACKAGE_PREPARE_FAILURE_WRONG_FILECOUNT", + "value": 4 + }, + { + "name": "ADUC_ERC_APT_HANDLER_GET_FILEENTITY_FAILURE", + "value": 5 + }, + { + "name": "ADUC_ERC_APT_HANDLER_INSTALLCRITERIA_PERSIST_FAILURE", + "value": 6 + }, + { + "name": "ADUC_ERC_APT_HANDLER_MISSING_INSTALLED_CRITERIA", + "value": 7 + }, + { + "name": "ADUC_ERC_APT_HANDLER_PACKAGE_DOWNLOAD_FAILURE", + "value": 256 + }, + { + "name": "ADUC_ERC_APT_HANDLER_DOWNLOAD_FAILED_TO_GET_CONFIG_INSTANCE", + "value": 257 + }, + { + "name": "ADUC_ERC_APT_HANDLER_PACKAGE_INSTALL_FAILURE", + "value": 512 + }, + { + "name": "ADUC_ERC_APT_HANDLER_INSTALL_FAILED_TO_GET_CONFIG_INSTANCE", + "value": 513 + }, + { + "name": "ADUC_ERC_APT_HANDLER_PACKAGE_CANCEL_FAILURE", + "value": 1024 + } + ] + }, + { + "code": 3, + "doc_string": "Results that originate from the simulator, only included here for completeness", + "name": "ADUC_CONTENT_HANDLER_SIMULATOR", + "results": [] + }, + { + "code": 4, + "doc_string": "Results that originate from the steps handler part of the step handlers", + "name": "ADUC_CONTENT_HANDLER_STEPS", + "results": [ + { + "name": "ADUC_ERC_STEPS_HANDLER_GET_FILE_ENTITY_FAILURE", + "value": 1 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INVALID_CHILD_MANIFEST_FILENAME", + "value": 2 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_CHILD_WORKFLOW_CREATE_FAILED", + "value": 3 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_CHILD_WORKFLOW_INSERT_FAILED", + "value": 4 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_GET_REF_STEP_COMPATIBILITY_FAILED", + "value": 5 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_SET_SELECTED_COMPONENTS_FAILED", + "value": 6 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_GET_STEP_COMPATIBILITY_FAILED", + "value": 7 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_SET_SELECTED_COMPONENTS_FAILURE", + "value": 8 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_NESTED_REFERENCE_STEP_DETECTED", + "value": 9 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INVALID_COMPONENTS_DATA", + "value": 10 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_CREATE_SANDBOX_FAILURE", + "value": 11 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_DOWNLOAD_FAILURE_UNKNOWNEXCEPTION", + "value": 256 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_DOWNLOAD_FAILURE_MISSING_CHILD_WORKFLOW", + "value": 257 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_DOWNLOAD_UNKNOWN_EXCEPTION_DOWNLOAD_CONTENT", + "value": 258 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_ISINSTALLED_FAILURE_MISSING_CHILD_WORKFLOW", + "value": 501 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURES_UNKNOWNEXCEPTION", + "value": 512 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURE_MISSING_CHILD_WORKFLOW", + "value": 513 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_INSTALL_CHILD_STEP", + "value": 514 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_APPLY_CHILD_STEP", + "value": 515 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_BACKUP_CHILD_STEP", + "value": 516 + }, + { + "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_RESTORE_CHILD_STEP", + "value": 517 + } + ] + }, + { + "code": 5, + "doc_string": "Results that originate from the script handler part of the step handlers", + "name": "ADUC_CONTENT_HANDLER_SCRIPT", + "results": [ + { + "name": "ADUC_ERC_SCRIPT_HANDLER_ERROR_NONE", + "value": 0 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_SET_SELECTED_COMPONENTS_FAILURE", + "value": 1 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_MISSING_INSTALLED_CRITERIA", + "value": 2 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_TOO_MANY_COMPONENTS", + "value": 3 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_MISSING_PRIMARY_SCRIPT_FILE", + "value": 4 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_MISSING_SCRIPTFILENAME_PROPERTY", + "value": 5 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_CREATE_SANDBOX_FAILURE", + "value": 6 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INVALID_COMPONENTS_DATA", + "value": 7 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_ERROR_NULL_WORKFLOW", + "value": 257 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_FAILURE_INVALID_FILE_COUNT", + "value": 258 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_FAILURE_GET_PRIMARY_FILE_ENTITY", + "value": 259 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_FAILURE_GET_PAYLOAD_FILE_ENTITY", + "value": 260 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_PAYLOAD_FILE_FAILURE_UNKNOWNEXCEPTION", + "value": 510 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_PRIMARY_FILE_FAILURE_UNKNOWNEXCEPTION", + "value": 511 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_ERROR_NULL_WORKFLOW", + "value": 513 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_INSTALLITEM_BAD_DATA", + "value": 514 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_INSTALLITEM_NO_UPDATE_TYPE", + "value": 515 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_MISSING_PRIMARY_SCRIPT_FILE", + "value": 516 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_PARSE_RESULT_FILE", + "value": 517 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_SCRIPT_RESULT_EXTENDEDRESULTCODE_ZERO", + "value": 518 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILED_TO_GET_CONFIG_INSTANCE", + "value": 519 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_UNKNOWNEXCEPTION", + "value": 767 + }, + { + "name": "ADUC_ERC_SCRIPT_HANDLER_APPLY_FAILURE_UNKNOWNEXCEPTION", + "value": 1023 + } + ] + }, + { + "code": 32, + "doc_string": "indicates errors from custom step handlers, only included here for completeness", + "name": "ADUC_CONTENT_HANDLER_EXTERNAL", + "results": [] + } + ], "code": 3, - "doc_string": "Results that originate from the simulator, only included here for completeness", - "name": "ADUC_CONTENT_HANDLER_SIMULATOR", - "results": [] - }, - { + "doc_string": "indicates errors from a step handler", + "name": "ADUC_FACILITY_EXTENSION_UPDATE_CONTENT_HANDLER" + }, + { + "components": [ + { + "code": 0, + "doc_string": "indicates common errors from the downloader extension", + "name": "ADUC_CONTENT_DOWNLOADER_COMMON", + "results": [ + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_CREATE_FAILURE_NO_SYMBOL", + "value": 1 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_INITIALIZEPROC_NOTIMP", + "value": 2 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_DOWNLOADPROC_NOTIMP", + "value": 3 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_INITIALIZE_EXCEPTION", + "value": 4 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_DOWNLOAD_EXCEPTION", + "value": 5 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_FILE_ENTITY", + "value": 6 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_DOWNLOAD_URI", + "value": 7 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_FILE_HASH_TYPE_NOT_SUPPORTED", + "value": 8 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_BAD_CHILD_MANIFEST_FILE_PATH", + "value": 9 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_CANNOT_DELETE_EXISTING_FILE", + "value": 10 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_FILE_ENTITY_NO_HASHES", + "value": 11 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_FILE_HASH", + "value": 12 + }, + { + "name": "ADUC_ERC_CONTENT_DOWNLOADER_UNSUPPORTED_CONTRACT_VERSION", + "value": 13 + } + ] + }, + { + "code": 1, + "doc_string": "indicates errors from Delivery Optimization agent. ", + "name": "ADUC_CONTENT_DOWNLOADER_DELIVERY_OPTIMIZATION", + "results": [ + { + "name": "ADUC_ERROR_DELIVERY_OPTIMIZATION_DOWNLOADER_NOT_INITIALIZE", + "value": 1 + }, + { + "name": "ADUC_ERROR_DELIVERY_OPTIMIZATION_DOWNLOADER_BAD_INIT_DATA", + "value": 2 + } + ] + }, + { + "code": 2, + "doc_string": "indicates errors from Simple Http Downloader. ", + "name": "ADUC_CONTENT_DOWNLOADER_SIMPLE_HTTP_DOWNLOADER", + "results": [] + }, + { + "code": 3, + "doc_string": "indicates errors from Curl Downloader.", + "name": "ADUC_CONTENT_DOWNLOADER_CURL_DOWNLOADER", + "results": [ + { + "name": "ADUC_ERROR_CURL_DOWNLOADER_INVALID_FILE_HASH", + "value": 1 + } + ] + } + ], "code": 4, - "doc_string": "Results that originate from the steps handler part of the step handlers", - "name": "ADUC_CONTENT_HANDLER_STEPS", - "results": [ - { - "name": "ADUC_ERC_STEPS_HANDLER_GET_FILE_ENTITY_FAILURE", - "value": 1 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INVALID_CHILD_MANIFEST_FILENAME", - "value": 2 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_CHILD_WORKFLOW_CREATE_FAILED", - "value": 3 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_CHILD_WORKFLOW_INSERT_FAILED", - "value": 4 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_GET_REF_STEP_COMPATIBILITY_FAILED", - "value": 5 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_SET_SELECTED_COMPONENTS_FAILED", - "value": 6 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_GET_STEP_COMPATIBILITY_FAILED", - "value": 7 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_SET_SELECTED_COMPONENTS_FAILURE", - "value": 8 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_NESTED_REFERENCE_STEP_DETECTED", - "value": 9 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INVALID_COMPONENTS_DATA", - "value": 10 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_CREATE_SANDBOX_FAILURE", - "value": 11 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_DOWNLOAD_FAILURE_UNKNOWNEXCEPTION", - "value": 256 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_DOWNLOAD_FAILURE_MISSING_CHILD_WORKFLOW", - "value": 257 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_DOWNLOAD_UNKNOWN_EXCEPTION_DOWNLOAD_CONTENT", - "value": 258 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURES_UNKNOWNEXCEPTION", - "value": 512 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_ISINSTALLED_FAILURE_MISSING_CHILD_WORKFLOW", - "value": 501 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURE_MISSING_CHILD_WORKFLOW", - "value": 513 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_INSTALL_CHILD_STEP", - "value": 514 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_APPLY_CHILD_STEP", - "value": 515 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_BACKUP_CHILD_STEP", - "value": 516 - }, - { - "name": "ADUC_ERC_STEPS_HANDLER_INSTALL_UNKNOWN_EXCEPTION_RESTORE_CHILD_STEP", - "value": 517 - } - ] - }, - { + "doc_string": "indicates errors from CONTENT_DOWNLOADER Extension", + "name": "ADUC_FACILITY_EXTENSION_CONTENT_DOWNLOADER" + }, + { + "components": [], "code": 5, - "doc_string": "Results that originate from the script handler part of the step handlers", - "name": "ADUC_CONTENT_HANDLER_SCRIPT", - "results": [ - { - "name": "ADUC_ERC_SCRIPT_HANDLER_ERROR_NONE", - "value": 0 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_SET_SELECTED_COMPONENTS_FAILURE", - "value": 1 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_MISSING_INSTALLED_CRITERIA", - "value": 2 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_TOO_MANY_COMPONENTS", - "value": 3 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_MISSING_PRIMARY_SCRIPT_FILE", - "value": 4 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_MISSING_SCRIPTFILENAME_PROPERTY", - "value": 5 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_CREATE_SANDBOX_FAILURE", - "value": 6 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INVALID_COMPONENTS_DATA", - "value": 7 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_ERROR_NULL_WORKFLOW", - "value": 257 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_FAILURE_INVALID_FILE_COUNT", - "value": 258 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_FAILURE_GET_PRIMARY_FILE_ENTITY", - "value": 259 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_FAILURE_GET_PAYLOAD_FILE_ENTITY", - "value": 260 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_PAYLOAD_FILE_FAILURE_UNKNOWNEXCEPTION", - "value": 510 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_PRIMARY_FILE_FAILURE_UNKNOWNEXCEPTION", - "value": 511 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_ERROR_NULL_WORKFLOW", - "value": 513 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_INSTALLITEM_BAD_DATA", - "value": 514 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_INSTALLITEM_NO_UPDATE_TYPE", - "value": 515 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_MISSING_PRIMARY_SCRIPT_FILE", - "value": 516 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_PARSE_RESULT_FILE", - "value": 517 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_SCRIPT_RESULT_EXTENDEDRESULTCODE_ZERO", - "value": 518 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILED_TO_GET_CONFIG_INSTANCE", - "value": 519 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_INSTALL_FAILURE_UNKNOWNEXCEPTION", - "value": 767 - }, - { - "name": "ADUC_ERC_SCRIPT_HANDLER_APPLY_FAILURE_UNKNOWNEXCEPTION", - "value": 1023 - } - ] - }, - { - "code": 32, - "doc_string": "indicates errors from custom step handlers, only included here for completeness", - "name": "ADUC_CONTENT_HANDLER_EXTERNAL", - "results": [] - } - ], - "code": 3, - "doc_string": "indicates errors from a step handler", - "name": "ADUC_FACILITY_EXTENSION_UPDATE_CONTENT_HANDLER" - }, - { - "components": [ - { - "code": 0, - "doc_string": "indicates common errors from the downloader extension", - "name": "ADUC_CONTENT_DOWNLOADER_COMMON", - "results": [ - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_CREATE_FAILURE_NO_SYMBOL", - "value": 1 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_INITIALIZEPROC_NOTIMP", - "value": 2 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_DOWNLOADPROC_NOTIMP", - "value": 3 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_INITIALIZE_EXCEPTION", - "value": 4 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_DOWNLOAD_EXCEPTION", - "value": 5 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_FILE_ENTITY", - "value": 6 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_DOWNLOAD_URI", - "value": 7 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_FILE_HASH_TYPE_NOT_SUPPORTED", - "value": 8 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_BAD_CHILD_MANIFEST_FILE_PATH", - "value": 9 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_CANNOT_DELETE_EXISTING_FILE", - "value": 10 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_FILE_ENTITY_NO_HASHES", - "value": 11 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_INVALID_FILE_HASH", - "value": 12 - }, - { - "name": "ADUC_ERC_CONTENT_DOWNLOADER_UNSUPPORTED_CONTRACT_VERSION", - "value": 13 - } - ] - }, - { - "code": 1, - "doc_string": "indicates errors from Delivery Optimization agent. ", - "name": "ADUC_CONTENT_DOWNLOADER_DELIVERY_OPTIMIZATION", - "results": [ - { - "name": "ADUC_ERROR_DELIVERY_OPTIMIZATION_DOWNLOADER_NOT_INITIALIZE", - "value": 1 - }, - { - "name": "ADUC_ERROR_DELIVERY_OPTIMIZATION_DOWNLOADER_BAD_INIT_DATA", - "value": 2 - } - ] - }, - { - "code": 2, - "doc_string": "indicates errors from Simple Http Downloader. ", - "name": "ADUC_CONTENT_DOWNLOADER_SIMPLE_HTTP_DOWNLOADER", - "results": [] - }, - { - "code": 3, - "doc_string": "indicates errors from Curl Downloader.", - "name": "ADUC_CONTENT_DOWNLOADER_CURL_DOWNLOADER", - "results": [ - { - "name": "ADUC_ERROR_CURL_DOWNLOADER_INVALID_FILE_HASH", - "value": 1 - } - ] - } - ], - "code": 4, - "doc_string": "indicates errors from CONTENT_DOWNLOADER Extension", - "name": "ADUC_FACILITY_EXTENSION_CONTENT_DOWNLOADER" - }, - { - "components": [], - "code": 5, - "doc_string": "indicates errors from COMMUNICATION PROVIDER Extension.", - "name": "ADUC_FACILITY_EXTENSION_COMMUNICATION_PROVIDER" - }, - { - "components": [], - "code": 6, - "doc_string": "indicates errors from LOG PROVIDER Extension.", - "name": "ADUC_FACILITY_EXTENSION_LOG_PROVIDER" - }, - { - "components": [ - { - "code": 0, - "doc_string": "General errors from the Extension Component Enumerator", - "name": "ADUC_COMPONENT_EXTENSION_ENUMERATOR_COMMON", - "results": [ - { - "name": "ADUC_ERC_COMPONENT_ENUMERATOR_GETALLCOMPONENTS_NOTIMP", - "value": 1 - }, - { - "name": "ADUC_ERC_COMPONENT_ENUMERATOR_SELECTCOMPONENTS_NOTIMP", - "value": 2 - }, - { - "name": "ADUC_ERC_COMPONENT_ENUMERATOR_FREECOMPONENTSDATASTRING_NOTIMP", - "value": 3 - }, - { - "name": "ADUC_ERC_COMPONENT_ENUMERATOR_EXCEPTION_GETALLCOMPONENTS", - "value": 4 - }, - { - "name": "ADUC_ERC_COMPONENT_ENUMERATOR_EXCEPTION_SELECTCOMPONENTS", - "value": 5 - }, - { - "name": "ADUC_ERC_COMPONENT_ENUMERATOR_EXCEPTION_FREECOMPONENTSDATASTRING", - "value": 6 - }, - { - "name": "ADUC_ERC_COMPONENT_ENUMERATOR_UNSUPPORTED_CONTRACT_VERSION", - "value": 7 - } - ] - } - ], - "code": 7, - "doc_string": "indicates errors from COMPONENT ENUMERATOR Extension. ", - "name": "ADUC_FACILITY_EXTENSION_COMPONENT_ENUMERATOR" - }, - { - "components": [ - { - "code": 3, - "doc_string": "indicates errors from parsers.", - "name": "ADUC_COMPONENT_UPDATE_DATA_PARSER", - "results": [ - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_INVALID_ACTION_JSON", - "value": 0 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MANIFEST_VALIDATION_FAILED", - "value": 1 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_ACTION", - "value": 2 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_ID", - "value": 3 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_TYPE", - "value": 4 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_UPDATE_TYPE", - "value": 5 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_INSTALLEDCRITERIA", - "value": 6 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_FILES_OR_FILEURLS", - "value": 7 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_MANIFEST", - "value": 8 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_UPDATE_MANIFEST", - "value": 9 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_UNSUPPORTED_UPDATE_MANIFEST_VERSION", - "value": 10 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MISSING_DETACHED_UPDATE_MANIFEST_ENTITY", - "value": 11 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST", - "value": 12 - }, - { - "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_DOWNLOAD_FAILED", - "value": 13 - } - ] - }, - { - "code": 4, - "doc_string": "indicates errors from Workflow Utilities or Function.", - "name": "ADUC_COMPONENT_WORKFLOW_UTIL", - "results": [ - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM", - "value": 1 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_NO_MEM", - "value": 2 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_ACTION_JSON_STRING", - "value": 3 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_ACTION_JSON_FILE", - "value": 4 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_UPDATE_ID", - "value": 5 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_FROM_BASE_FAILURE", - "value": 6 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_MANIFEST_FROM_BASE_FAILURE", - "value": 7 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_PARSE_INSTRUCTION_ENTRY_FAILURE", - "value": 8 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_PARSE_INSTRUCTION_ENTRY_NO_UPDATE_TYPE", - "value": 9 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_SET_UPDATE_TYPE_FAILURE", - "value": 10 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_STEP_INDEX", - "value": 11 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_PARSE_STEP_ENTRY_NO_HANDLER_TYPE", - "value": 12 - }, - { - "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_COPY_HANDLER_PROPERTIES_FAILED", - "value": 13 - } - ] - } - ], - "code": 8, - "doc_string": "indicates errors from utility functions.", - "name": "ADUC_FACILITY_UTILITY" - }, - { - "components": [ - { - "code": 0, - "doc_string": "0x00 - 0x07 are reserved for download handler. Indicates errors from extension manager download handler logic.", - "name": "ADUC_COMPONENT_DOWNLOAD_HANDLER_EXTENSION_MANAGER", - "results": [ - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_CREATE_FAILURE_CREATE", - "value": 1 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_UNSUPPORTED_CONTRACT_VERSION", - "value": 2 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_CREATE_FACTORY_INSTANCE", - "value": 3 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_HELPER_BAD_ARG", - "value": 4 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSIBILITY_GET_CONTRACT", - "value": 5 - } - ] - }, - { - "code": 1, - "doc_string": "Indicates errors with usage of download handler plugin shared libraries.", - "name": "ADUC_COMPONENT_DOWNLOAD_HANDLER_PLUGIN", - "results": [ - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_ON_UPDATE_WORKFLOW_COMPLETED_FAILURE", - "value": 1 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_MISSING_EXPORT_SYMBOL", - "value": 2 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_EXCEPTION", - "value": 3 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_ON_UPDATE_WORKFLOW_COMPLETED_STDEXCEPTION", - "value": 4 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_ON_UPDATE_WORKFLOW_COMPLETED_NONSTDEXCEPTION", - "value": 5 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_GETCONTRACTINFO_STDEXCEPTION", - "value": 6 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_GETCONTRACTINFO_NONSTDEXCEPTION", - "value": 7 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_PROCESSUPDATE_STDEXCEPTION", - "value": 8 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_PROCESSUPDATE_NONSTDEXCEPTION", - "value": 9 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_ONUPDATEWORKFLOWCOMPLETED", - "value": 10 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_GETCONTRACTINFO", - "value": 11 - }, - { - "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_PROCESSUPDATE", - "value": 12 - } - ] - }, - { + "doc_string": "indicates errors from COMMUNICATION PROVIDER Extension.", + "name": "ADUC_FACILITY_EXTENSION_COMMUNICATION_PROVIDER" + }, + { + "components": [], + "code": 6, + "doc_string": "indicates errors from LOG PROVIDER Extension.", + "name": "ADUC_FACILITY_EXTENSION_LOG_PROVIDER" + }, + { + "components": [ + { + "code": 0, + "doc_string": "General errors from the Extension Component Enumerator", + "name": "ADUC_COMPONENT_EXTENSION_ENUMERATOR_COMMON", + "results": [ + { + "name": "ADUC_ERC_COMPONENT_ENUMERATOR_GETALLCOMPONENTS_NOTIMP", + "value": 1 + }, + { + "name": "ADUC_ERC_COMPONENT_ENUMERATOR_SELECTCOMPONENTS_NOTIMP", + "value": 2 + }, + { + "name": "ADUC_ERC_COMPONENT_ENUMERATOR_FREECOMPONENTSDATASTRING_NOTIMP", + "value": 3 + }, + { + "name": "ADUC_ERC_COMPONENT_ENUMERATOR_EXCEPTION_GETALLCOMPONENTS", + "value": 4 + }, + { + "name": "ADUC_ERC_COMPONENT_ENUMERATOR_EXCEPTION_SELECTCOMPONENTS", + "value": 5 + }, + { + "name": "ADUC_ERC_COMPONENT_ENUMERATOR_EXCEPTION_FREECOMPONENTSDATASTRING", + "value": 6 + }, + { + "name": "ADUC_ERC_COMPONENT_ENUMERATOR_UNSUPPORTED_CONTRACT_VERSION", + "value": 7 + } + ] + } + ], + "code": 7, + "doc_string": "indicates errors from COMPONENT ENUMERATOR Extension. ", + "name": "ADUC_FACILITY_EXTENSION_COMPONENT_ENUMERATOR" + }, + { + "components": [ + { + "code": 3, + "doc_string": "indicates errors from parsers.", + "name": "ADUC_COMPONENT_UPDATE_DATA_PARSER", + "results": [ + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_INVALID_ACTION_JSON", + "value": 0 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MANIFEST_VALIDATION_FAILED", + "value": 1 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_ACTION", + "value": 2 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_ID", + "value": 3 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_TYPE", + "value": 4 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_UPDATE_TYPE", + "value": 5 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_INSTALLEDCRITERIA", + "value": 6 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_FILES_OR_FILEURLS", + "value": 7 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_MANIFEST", + "value": 8 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_UPDATE_MANIFEST", + "value": 9 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_UNSUPPORTED_UPDATE_MANIFEST_VERSION", + "value": 10 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MISSING_DETACHED_UPDATE_MANIFEST_ENTITY", + "value": 11 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST", + "value": 12 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_DOWNLOAD_FAILED", + "value": 13 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST_JSON_FILE", + "value": 14 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_MISSING_UPDATEMANIFEST_PROPERTY", + "value": 15 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_WORKFLOW_ACTION", + "value": 16 + }, + { + "name": "ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_EMPTY_OR_MISSING_ROOTKEY_PKG_URL", + "value": 17 + } + ] + }, + { + "code": 4, + "doc_string": "indicates errors from Workflow Utilities or Function.", + "name": "ADUC_COMPONENT_WORKFLOW_UTIL", + "results": [ + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM", + "value": 1 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_NO_MEM", + "value": 2 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_ACTION_JSON_STRING", + "value": 3 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_ACTION_JSON_FILE", + "value": 4 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_UPDATE_ID", + "value": 5 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_FROM_BASE_FAILURE", + "value": 6 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_MANIFEST_FROM_BASE_FAILURE", + "value": 7 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_PARSE_INSTRUCTION_ENTRY_FAILURE", + "value": 8 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_PARSE_INSTRUCTION_ENTRY_NO_UPDATE_TYPE", + "value": 9 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_SET_UPDATE_TYPE_FAILURE", + "value": 10 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_INVALID_STEP_INDEX", + "value": 11 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_PARSE_STEP_ENTRY_NO_HANDLER_TYPE", + "value": 12 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_COPY_HANDLER_PROPERTIES_FAILED", + "value": 13 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PROPERTYUPDATE_JSON_FILE", + "value": 14 + }, + { + "name": "ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PROPERTYUPDATE_JSON_STRING", + "value": 15 + } + ] + }, + { + "code": 5, + "doc_string": "indicates errors from RootKeyPackage Utilities or Function.", + "name": "ADUC_COMPONENT_ROOTKEYPKG_UTIL", + "results": [ + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_UNEXPECTED", + "value": 1 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG", + "value": 2 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_JSON", + "value": 3 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_VERSION", + "value": 4 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PUBLISHED", + "value": 5 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDROOTKEYS", + "value": 6 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_HASHING_PROPERTY_ALG", + "value": 7 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_SIGNATURE_PROPERTY_ALG", + "value": 8 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_HASH_OR_SIG", + "value": 9 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDSIGNINGKEYS", + "value": 10 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_KEYTYPE", + "value": 11 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_ROOTKEYS", + "value": 12 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PROTECTED", + "value": 13 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_SIGNATURES", + "value": 14 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_ROOTKEYS_EMPTY", + "value": 17 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_SIGNATURES_EMPTY", + "value": 18 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_MODULUS", + "value": 19 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_HASH_ALGORITHM", + "value": 20 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_SIGNING_ALGORITHM", + "value": 21 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_ENCODING", + "value": 22 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_KEY_ID", + "value": 23 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_UNSUPPORTED_KEYTYPE", + "value": 24 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_RSA_PARAMETERS", + "value": 25 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_SIGNATURES_ELEMENT", + "value": 26 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_DISABLEDSIGNINGKEYS_ELEMENT", + "value": 27 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_EXPONENT", + "value": 28 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_BADARG", + "value": 29 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_MKDIR_DWNLD_FOLDER", + "value": 30 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_URL_BAD_PATH", + "value": 31 + } + ] + }, + { + "code": 6, + "doc_string": "indicates errors from RootKey Utilities or function", + "name": "ADUC_COMPONENT_ROOTKEY_UTIL", + "results": [ + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_UNEXPECTED", + "value": 1 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_HARDCODED_ROOTKEY_LOAD_FAILED", + "value": 2 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_FOR_KEY_NOT_FOUND", + "value": 3 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_VALIDATION_FAILED", + "value": 4 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_STORE_FAILED", + "value": 5 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_BAD_ARGS", + "value": 6 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANNOT_WRITE_PACKAGE_TO_STORE", + "value": 7 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_RENAME_TO_STORE", + "value": 8 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_LOAD_FROM_STORE", + "value": 9 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_FAILED_SERIALIZE_TO_STRING", + "value": 10 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_NO_ROOTKEY_FOUND_FOR_KEYID", + "value": 11 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERRNOMEM", + "value": 12 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_ROOTKEY_IS_DISABLED", + "value": 13 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_MISSING_SIGNING_KEY", + "value": 14 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_LOCAL_STORE_UNINITIALIZED", + "value": 15 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_PAYLOAD_BAD_JSON", + "value": 16 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_KEY_TYPE", + "value": 17 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_ALG", + "value": 18 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_N", + "value": 19 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_EXPONENT", + "value": 20 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERR_GEN_PUBKEY", + "value": 21 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERR_CREATE_HASH_PUBKEY", + "value": 22 + }, + { + "name": "ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_DOWNLOAD_EXCEPTION", + "value": 23 + } + ] + }, + { + "code": 7, + "doc_string": "indicates errors from url utility.", + "name": "ADUC_COMPONENT_URL_UTIL", + "results": [ + { + "name": "ADUC_ERC_UTILITIES_URL_BAD_ARG", + "value": 1 + }, + { + "name": "ADUC_ERC_UTILITIES_URL_BAD_URL", + "value": 2 + }, + { + "name": "ADUC_ERC_UTILITIES_URL_BAD_PATH", + "value": 3 + }, + { + "name": "ADUC_ERC_UTILITIES_URL_PATH_COPY", + "value": 4 + } + ] + } + ], "code": 8, - "doc_string": "0x08 - 0x0F are reserved for Delta download handler. Indicates errors in Delta Download Handler extension top-level logic.", - "name": "ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_COMMON", - "results": [ - { - "name": "ADUC_ERC_DDH_BAD_ARGS", - "value": 1 - }, - { - "name": "ADUC_ERC_DDH_RELATEDFILE_NO_PROPERTIES", - "value": 2 - }, - { - "name": "ADUC_ERC_DDH_RELATEDFILE_BAD_OR_MISSING_HASH_PROPERTIES", - "value": 3 - }, - { - "name": "ADUC_ERC_DDH_MAKE_DELTA_UPDATE_PATH", - "value": 4 - }, - { - "name": "ADUC_ERC_DDH_PROCESSOR_LOAD_LIB", - "value": 5 - }, - { - "name": "ADUC_ERC_DDH_PROCESSOR_ENSURE_SYMBOLS", - "value": 6 - }, - { - "name": "ADUC_ERC_DDH_PROCESSOR_CREATE_SESSION", - "value": 7 - }, - { - "name": "ADUC_ERC_DDH_SOURCE_UPDATE_CACHE_MISS", - "value": 8 - } - ] - }, - { + "doc_string": "indicates errors from utility functions.", + "name": "ADUC_FACILITY_UTILITY" + }, + { + "components": [ + { + "code": 0, + "doc_string": "0x00 - 0x07 are reserved for download handler. Indicates errors from extension manager download handler logic.", + "name": "ADUC_COMPONENT_DOWNLOAD_HANDLER_EXTENSION_MANAGER", + "results": [ + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_CREATE_FAILURE_CREATE", + "value": 1 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_UNSUPPORTED_CONTRACT_VERSION", + "value": 2 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_CREATE_FACTORY_INSTANCE", + "value": 3 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_HELPER_BAD_ARG", + "value": 4 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_EXTENSIBILITY_GET_CONTRACT", + "value": 5 + } + ] + }, + { + "code": 1, + "doc_string": "Indicates errors with usage of download handler plugin shared libraries.", + "name": "ADUC_COMPONENT_DOWNLOAD_HANDLER_PLUGIN", + "results": [ + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_ON_UPDATE_WORKFLOW_COMPLETED_FAILURE", + "value": 1 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_MISSING_EXPORT_SYMBOL", + "value": 2 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_EXCEPTION", + "value": 3 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_ON_UPDATE_WORKFLOW_COMPLETED_STDEXCEPTION", + "value": 4 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_ON_UPDATE_WORKFLOW_COMPLETED_NONSTDEXCEPTION", + "value": 5 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_GETCONTRACTINFO_STDEXCEPTION", + "value": 6 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_GETCONTRACTINFO_NONSTDEXCEPTION", + "value": 7 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_PROCESSUPDATE_STDEXCEPTION", + "value": 8 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_PROCESSUPDATE_NONSTDEXCEPTION", + "value": 9 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_ONUPDATEWORKFLOWCOMPLETED", + "value": 10 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_GETCONTRACTINFO", + "value": 11 + }, + { + "name": "ADUC_ERC_DOWNLOAD_HANDLER_PLUGIN_EXPORT_CALL_PROCESSUPDATE", + "value": 12 + } + ] + }, + { + "code": 8, + "doc_string": "0x08 - 0x0F are reserved for Delta download handler. Indicates errors in Delta Download Handler extension top-level logic.", + "name": "ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_COMMON", + "results": [ + { + "name": "ADUC_ERC_DDH_BAD_ARGS", + "value": 1 + }, + { + "name": "ADUC_ERC_DDH_RELATEDFILE_NO_PROPERTIES", + "value": 2 + }, + { + "name": "ADUC_ERC_DDH_RELATEDFILE_BAD_OR_MISSING_HASH_PROPERTIES", + "value": 3 + }, + { + "name": "ADUC_ERC_DDH_MAKE_DELTA_UPDATE_PATH", + "value": 4 + }, + { + "name": "ADUC_ERC_DDH_PROCESSOR_LOAD_LIB", + "value": 5 + }, + { + "name": "ADUC_ERC_DDH_PROCESSOR_ENSURE_SYMBOLS", + "value": 6 + }, + { + "name": "ADUC_ERC_DDH_PROCESSOR_CREATE_SESSION", + "value": 7 + }, + { + "name": "ADUC_ERC_DDH_SOURCE_UPDATE_CACHE_MISS", + "value": 8 + } + ] + }, + { + "code": 9, + "doc_string": "Indicates errors in Delta Download handler extension Source Update Cache.", + "name": "ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_SOURCE_UPDATE_CACHE", + "results": [ + { + "name": "ADUC_ERC_MOVE_PREPURGE", + "value": 1 + }, + { + "name": "ADUC_ERC_MOVE_PAYLOAD", + "value": 2 + }, + { + "name": "ADUC_ERC_MOVE_POSTPURGE", + "value": 3 + }, + { + "name": "ADUC_ERC_MOVE_CREATE_CACHE_PATH", + "value": 4 + }, + { + "name": "ADUC_ERC_MOVE_COPYFALLBACK", + "value": 5 + }, + { + "name": "ADUC_ERC_LOOKUP_CREATE_PATH", + "value": 6 + }, + { + "name": "ADUC_ERC_MISSING_SOURCE_SANDBOX_FILE", + "value": 7 + } + ] + }, + { + "code": 10, + "doc_string": "error code for errors from delta processor API", + "name": "ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_DELTA_PROCESSOR", + "results": [] + } + ], "code": 9, - "doc_string": "Indicates errors in Delta Download handler extension Source Update Cache.", - "name": "ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_SOURCE_UPDATE_CACHE", - "results": [ - { - "name": "ADUC_ERC_MOVE_PREPURGE", - "value": 1 - }, - { - "name": "ADUC_ERC_MOVE_PAYLOAD", - "value": 2 - }, - { - "name": "ADUC_ERC_MOVE_POSTPURGE", - "value": 3 - }, - { - "name": "ADUC_ERC_MOVE_CREATE_CACHE_PATH", - "value": 4 - }, - { - "name": "ADUC_ERC_MOVE_COPYFALLBACK", - "value": 5 - }, - { - "name": "ADUC_ERC_LOOKUP_CREATE_PATH", - "value": 6 - }, - { - "name": "ADUC_ERC_MISSING_SOURCE_SANDBOX_FILE", - "value": 7 - } - ] - }, - { + "doc_string": "Indicates errors from download handler infrastructure or download handler extensions.", + "name": "ADUC_FACILITY_DOWNLOAD_HANDLER" + }, + { + "components": [ + { + "code": 0, + "doc_string": "indicates extended result codes for root key workflow.", + "name": "ADUC_COMPONENT_ROOTKEY_WORKFLOW", + "results": [ + { + "name": "ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_PARSE", + "value": 1 + }, + { + "name": "ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_SERIALIZE", + "value": 2 + }, + { + "name": "ADUC_ERC_ROOTKEY_STORE_PATH_CREATE", + "value": 3 + }, + { + "name": "ADUC_ERC_ROOTKEY_SIGNINGKEY_DISABLE_EVAL_INVALID_HASHALG", + "value": 4 + }, + { + "name": "ADUC_ERC_ROOTKEY_SIGNING_KEY_IS_DISABLED", + "value": 5 + }, + { + "name": "ADUC_ERC_ROOTKEY_PROD_PKG_ON_TEST_AGENT", + "value": 6 + }, + { + "name": "ADUC_ERC_ROOTKEY_TEST_PKG_ON_PROD_AGENT", + "value": 7 + }, + { + "name": "ADUC_ERC_ROOTKEY_PACKAGE_CHANGED", + "value": 8 + }, + { + "name": "ADUC_ERC_ROOTKEY_PKG_UNCHANGED", + "value": 4095 + } + ] + }, + { + "code": 1, + "doc_string": "indicates extended result codes for repacking root key downloader ones.", + "name": "ADUC_COMPONENT_ROOTKEY_DOWNLOADER", + "results": [] + }, + { + "code": 2, + "doc_string": "indicates extended result codes to pack JWSResult during update manifest validation.", + "name": "ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION", + "results": [] + } + ], "code": 10, - "doc_string": "error code for errors from delta processor API", - "name": "ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_DELTA_PROCESSOR", - "results": [] - } - ], - "code": 9, - "doc_string": "Indicates errors from download handler infrastructure or download handler extensions.", - "name": "ADUC_FACILITY_DOWNLOAD_HANDLER" - }, - { - "components": [], - "code": 10, - "doc_string": "unused", - "name": "ADUC_FACILITY_UNUSED_A" - }, - { - "components": [], - "code": 11, - "doc_string": "unused", - "name": "ADUC_FACILITY_UNUSED_B" - }, - { - "components": [], - "code": 12, - "doc_string": "unused", - "name": "ADUC_FACILITY_UNUSED_C" - }, - { - "components": [], - "code": 13, - "doc_string": "indicates errors from Delivery Optimization. DO returns HRESULT-like code. The HResult is transformed into our custom format.", - "name": "ADUC_FACILITY_DELIVERY_OPTIMIZATION" - }, - { - "components": [], - "code": 14, - "doc_string": "unused", - "name": "ADUC_FACILITY_UNUSED_E" - }, - { - "components": [], - "code": 15, - "doc_string": "unused", - "name": "ADUC_FACILITY_UNUSED_F" - } + "doc_string": "Indicates extended result codes for infrastructure management needed for proper functioning/integrity of update deployments.", + "name": "ADUC_FACILITY_INFRA_MGMT" + }, + { + "components": [], + "code": 11, + "doc_string": "unused", + "name": "ADUC_FACILITY_UNUSED_B" + }, + { + "components": [], + "code": 12, + "doc_string": "unused", + "name": "ADUC_FACILITY_UNUSED_C" + }, + { + "components": [], + "code": 13, + "doc_string": "indicates errors from Delivery Optimization. DO returns HRESULT-like code. The HResult is transformed into our custom format.", + "name": "ADUC_FACILITY_DELIVERY_OPTIMIZATION" + }, + { + "components": [], + "code": 14, + "doc_string": "unused", + "name": "ADUC_FACILITY_UNUSED_E" + }, + { + "components": [], + "code": 15, + "doc_string": "unused", + "name": "ADUC_FACILITY_UNUSED_F" + } ] - } +} diff --git a/scripts/install-deps.sh b/scripts/install-deps.sh index f1dc1b7ee..3937be390 100755 --- a/scripts/install-deps.sh +++ b/scripts/install-deps.sh @@ -86,7 +86,7 @@ catch2_cc="" catch2_cxx="" # Dependencies packages -aduc_packages=('git' 'make' 'build-essential' 'cmake' 'ninja-build' 'libcurl4-openssl-dev' 'libssl-dev' 'libxml2-dev' 'uuid-dev' 'python2.7' 'lsb-release' 'curl' 'wget' 'pkg-config') +aduc_packages=('git' 'make' 'build-essential' 'cmake' 'ninja-build' 'libcurl4-openssl-dev' 'libssl-dev' 'uuid-dev' 'python2.7' 'lsb-release' 'curl' 'wget' 'pkg-config') static_analysis_packages=('clang' 'clang-tidy' 'cppcheck') compiler_packages=('gcc' 'g++') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5cb3335ba..b78d5e4e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,12 @@ if (ADUC_TRACE_TARGET_DEPS) set_property (GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1) endif () +if (ADUC_USE_TEST_ROOT_KEYS) + set (EMBED_TEST_ROOT_KEYS 1) +else () + set (EMBED_TEST_ROOT_KEYS 0) +endif () + if (ADUC_WARNINGS_AS_ERRORS) if (MSVC) # Warnings as errors. @@ -69,6 +75,8 @@ set (ADU_EXTENSION_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/extensions/inc ${CMAKE_CURRENT_SOURCE_DIR}/adu_types/inc) add_subdirectory (libaducpal) +add_subdirectory (agent) +add_subdirectory (agent_orchestration) add_subdirectory (adu-shell) add_subdirectory (adu_types) add_subdirectory (adu_workflow) @@ -79,10 +87,9 @@ add_subdirectory (diagnostics_component) if (ADUC_BUILD_DOCUMENTATION) add_subdirectory (docs) endif () +add_subdirectory (extensions) add_subdirectory (logging) add_subdirectory (platform_layers) +add_subdirectory (rootkey_workflow) add_subdirectory (utils) -add_subdirectory (extensions) -add_subdirectory (agent) -add_subdirectory (agent_orchestration) diff --git a/src/adu_types/inc/aduc/types/adu_core.h b/src/adu_types/inc/aduc/types/adu_core.h index f98c8b16d..678101a75 100644 --- a/src/adu_types/inc/aduc/types/adu_core.h +++ b/src/adu_types/inc/aduc/types/adu_core.h @@ -271,6 +271,7 @@ typedef enum tagADUC_ResultCode ADUC_Result_Restore_RequiredReboot = 1106, /**< Succeeded. A deferred device reboot is required, to complete the task. */ ADUC_Result_Restore_RequiredImmediateAgentRestart = 1107, /**< Succeeded. An immediate agent restart is required, to complete the task. */ ADUC_Result_Restore_RequiredAgentRestart = 1108, /**< Succeeded. A deferred agent restart is required, to complete the task. */ + ADUC_Result_RootKey_Continue = 1200, /**< Succeeded. Rootkey package is current so continue with update processing. */ } ADUC_ResultCode; #define AducResultCodeIndicatesInProgress(resultCode) \ diff --git a/src/adu_types/inc/aduc/types/update_content.h b/src/adu_types/inc/aduc/types/update_content.h index 9dd967139..8723c8a11 100644 --- a/src/adu_types/inc/aduc/types/update_content.h +++ b/src/adu_types/inc/aduc/types/update_content.h @@ -65,9 +65,9 @@ EXTERN_C_BEGIN #define ADUCITF_FIELDNAME_RESULTCODE "resultCode" /** - * @brief JSON field name for ExtendedResultCode property. + * @brief JSON field name for ExtendedResultCodes property. */ -#define ADUCITF_FIELDNAME_EXTENDEDRESULTCODE "extendedResultCode" +#define ADUCITF_FIELDNAME_EXTENDEDRESULTCODES "extendedResultCodes" /** * @brief JSON field name for ResultDetails property. @@ -138,6 +138,11 @@ EXTERN_C_BEGIN */ #define ADUCITF_FIELDNAME_FILE_URLS "fileUrls" +/** + * @brief JSON field name for Root Key Package URL + */ +#define ADUCITF_FIELDNAME_ROOTKEY_PACKAGE_URL "rootKeyPackageUrl" + // // Update Manifest Field Values // diff --git a/src/adu_workflow/CMakeLists.txt b/src/adu_workflow/CMakeLists.txt index d7bc2c6db..33c20c92b 100644 --- a/src/adu_workflow/CMakeLists.txt +++ b/src/adu_workflow/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries ( aduc::download_handler_plugin aduc::logging aduc::parser_utils + aduc::root_key_utils aduc::system_utils aduc::workflow_data_utils aduc::workflow_utils) diff --git a/src/adu_workflow/src/agent_workflow.c b/src/adu_workflow/src/agent_workflow.c index b4923dd07..c1bf32128 100644 --- a/src/adu_workflow/src/agent_workflow.c +++ b/src/adu_workflow/src/agent_workflow.c @@ -31,6 +31,7 @@ #include "aduc/types/workflow.h" #include "aduc/workflow_data_utils.h" #include "aduc/workflow_utils.h" +#include "root_key_util.h" // RootKeyUtility_GetReportingErc #include @@ -242,15 +243,6 @@ typedef struct tagADUC_WorkflowHandlerMapEntry * AutoTransitionApplicableUpdateAction is equal to the current update action of the workflow data. */ const ADUC_WorkflowHandlerMapEntry workflowHandlerMap[] = { - { ADUCITF_WorkflowStep_ProcessDeployment, - /* calls operation */ ADUC_Workflow_MethodCall_ProcessDeployment, - /* and on completion calls */ ADUC_Workflow_MethodCall_ProcessDeployment_Complete, - /* on success, transitions to state */ ADUCITF_State_DeploymentInProgress, - /* on success auto-transitions to workflow step */ ADUCITF_WorkflowStep_Download, - /* on failure, transitions to state */ ADUCITF_State_Failed, - /* on failure auto-transitions to workflow step */ ADUCITF_WorkflowStep_Undefined, - }, - { ADUCITF_WorkflowStep_Download, /* calls operation */ ADUC_Workflow_MethodCall_Download, /* and on completion calls */ ADUC_Workflow_MethodCall_Download_Complete, @@ -407,10 +399,6 @@ void ADUC_Workflow_HandleStartupWorkflowData(ADUC_WorkflowData* currentWorkflowD } // There's a pending ProcessDeployment action in the twin. - // We need to make sure we don't report an 'idle' state, if we can resume or retry the action. - // In this case, we will set last reportedState to 'idle', so that we can continue. - ADUC_WorkflowData_SetLastReportedState(ADUCITF_State_Idle, currentWorkflowData); - ADUC_Workflow_HandleUpdateAction(currentWorkflowData); done: @@ -435,6 +423,12 @@ void ADUC_Workflow_HandlePropertyUpdate( workflow_set_force_update(nextWorkflow, forceUpdate); + ADUC_Result_t rootkeyErc = RootKeyUtility_GetReportingErc(); + if (rootkeyErc != 0) + { + workflow_add_erc(nextWorkflow, rootkeyErc); + } + if (IsAducResultCodeFailure(result.ResultCode)) { Log_Error("Invalid desired update action data. Update data: (%s)", propertyUpdateValue); @@ -1183,6 +1177,7 @@ static void CallDownloadHandlerOnUpdateWorkflowCompleted(const ADUC_WorkflowHand { ADUC_Result result; memset(&result, 0, sizeof(result)); + ADUC_FileEntity fileEntity; memset(&fileEntity, 0, sizeof(fileEntity)); @@ -1199,11 +1194,8 @@ static void CallDownloadHandlerOnUpdateWorkflowCompleted(const ADUC_WorkflowHand // NOTE: do not free the handle as it is owned by the DownloadHandlerFactory. DownloadHandlerHandle* handle = ADUC_DownloadHandlerFactory_LoadDownloadHandler(fileEntity.DownloadHandlerId); - if (handle == NULL) - { - Log_Error("Failed to load download handler."); - } - else + ADUC_FileEntity_Uninit(&fileEntity); + if (handle != NULL) { result = ADUC_DownloadHandlerPlugin_OnUpdateWorkflowCompleted(handle, workflowHandle); if (IsAducResultCodeFailure(result.ResultCode)) @@ -1213,11 +1205,9 @@ static void CallDownloadHandlerOnUpdateWorkflowCompleted(const ADUC_WorkflowHand result.ResultCode, result.ExtendedResultCode); - workflow_set_success_erc(workflowHandle, result.ExtendedResultCode); + workflow_add_erc(workflowHandle, result.ExtendedResultCode); } } - - ADUC_FileEntity_Uninit(&fileEntity); } } @@ -1336,27 +1326,6 @@ void ADUC_Workflow_MethodCall_Idle(ADUC_WorkflowData* workflowData) workflowData->WorkflowHandle = NULL; } -/** - * @brief Called to do ProcessDeployment. - * - * @param[in,out] methodCallData The metedata for the method call. - * @return Result code. - */ -ADUC_Result ADUC_Workflow_MethodCall_ProcessDeployment(ADUC_MethodCall_Data* methodCallData) -{ - UNREFERENCED_PARAMETER(methodCallData); - Log_Info("Workflow step: ProcessDeployment"); - - ADUC_Result result = { ADUC_Result_Success }; - return result; -} - -void ADUC_Workflow_MethodCall_ProcessDeployment_Complete(ADUC_MethodCall_Data* methodCallData, ADUC_Result result) -{ - UNREFERENCED_PARAMETER(methodCallData); - UNREFERENCED_PARAMETER(result); -} - /** * @brief Called to do download. * diff --git a/src/agent/CMakeLists.txt b/src/agent/CMakeLists.txt index f2b0d92f7..f94626bb5 100644 --- a/src/agent/CMakeLists.txt +++ b/src/agent/CMakeLists.txt @@ -16,14 +16,9 @@ endif () include (agentRules) -include (find_curl_and_import_libcurl) - compileasc99 () disablertti () -# Used to find and include the CURL::libcurl imported libary -find_curl_and_import_libcurl () - set (agent_c_files ./src/main.c ./src/health_management.c) add_executable (${target_name} ${agent_c_files}) @@ -68,17 +63,20 @@ target_compile_definitions ( # NOTE: the call to find_package for azure_c_shared_utility # must come before umqtt since their config.cmake files expect the aziotsharedutil target to already have been defined. -find_package (azure_c_shared_utility REQUIRED) +target_link_aziotsharedutil (${target_name} PRIVATE) + find_package (IotHubClient REQUIRED) find_package (umqtt REQUIRED) find_package (Parson REQUIRED) -target_link_aziotsharedutil (${target_name} PRIVATE) +# Windows needs all EXEs to have links to all potential libraries so this is included here +if (WIN32) + target_link_dosdk (${target_name} PRIVATE) +endif () target_link_libraries ( ${target_name} - PRIVATE aziotsharedutil - IotHubClient::iothub_client + PRIVATE IotHubClient::iothub_client umqtt aduc::adu_core_export_helpers aduc::adu_core_interface @@ -92,13 +90,13 @@ target_link_libraries ( aduc::eis_utils aduc::extension_manager aduc::extension_utils - aduc::https_proxy_utils aduc::iothub_communication_manager aduc::logging aduc::permission_utils aduc::pnp_helper aduc::shutdown_service aduc::system_utils + aduc::url_utils diagnostics_component::diagnostics_interface diagnostics_component::diagnostics_devicename) diff --git a/src/agent/adu_core_interface/CMakeLists.txt b/src/agent/adu_core_interface/CMakeLists.txt index 962ffe07e..d18d652a0 100644 --- a/src/agent/adu_core_interface/CMakeLists.txt +++ b/src/agent/adu_core_interface/CMakeLists.txt @@ -32,6 +32,9 @@ target_link_libraries ( aduc::logging aduc::parser_utils aduc::pnp_helper + aduc::reporting_utils + aduc::rootkeypackage_utils + aduc::rootkey_workflow aduc::workflow_data_utils aduc::workflow_utils Parson::parson) diff --git a/src/agent/adu_core_interface/src/adu_core_interface.c b/src/agent/adu_core_interface/src/adu_core_interface.c index c388d6927..4c681689f 100644 --- a/src/agent/adu_core_interface/src/adu_core_interface.c +++ b/src/agent/adu_core_interface/src/adu_core_interface.c @@ -16,7 +16,13 @@ #include "aduc/d2c_messaging.h" #include "aduc/hash_utils.h" #include "aduc/logging.h" +#include "aduc/reporting_utils.h" +#include "aduc/rootkey_workflow.h" +#include "aduc/rootkeypackage_do_download.h" +#include "aduc/rootkeypackage_types.h" +#include "aduc/rootkeypackage_utils.h" #include "aduc/string_c_utils.h" +#include "aduc/types/adu_core.h" #include "aduc/types/update_content.h" #include "aduc/workflow_data_utils.h" #include "aduc/workflow_utils.h" @@ -313,6 +319,67 @@ void AzureDeviceUpdateCoreInterface_Destroy(void** componentContext) *componentContext = NULL; } +/** + * @brief Update twin to report state transition before workflow processing has started. + * + * @param propertyValue The json value to use for reporting. + * @param deploymentState The final deployment state to report. + * @param workflowData The workflow data to receive the last reported state upon reporting success. + * @param result The result to be reported. + * @return true on reporting success. + */ +static bool ReportPreDeploymentProcessingState( + JSON_Value* propertyValue, ADUCITF_State deploymentState, ADUC_WorkflowData* workflowData, ADUC_Result result) +{ + JSON_Value* propertyValueCopy = NULL; + bool reportingSuccess = false; + + // Temp workflowData and workflow handle for reporting + ADUC_WorkflowData tmpWorkflowData; + memset(&tmpWorkflowData, 0, sizeof(tmpWorkflowData)); + + if (!ADUC_WorkflowData_InitWorkflowHandle(&tmpWorkflowData)) + { + goto done; + } + + // Synthesize workflowData current action and set a copy of the + // propertyValue to workflow UpdateActionObject, both of which are + // needed to generate the reporting json. + tmpWorkflowData.CurrentAction = ADUCITF_UpdateAction_ProcessDeployment; + propertyValueCopy = json_value_deep_copy(propertyValue); + if (propertyValueCopy == NULL) + { + goto done; + } + + if (!workflow_set_update_action_object(tmpWorkflowData.WorkflowHandle, json_object(propertyValueCopy))) + { + goto done; + } + + reportingSuccess = AzureDeviceUpdateCoreInterface_ReportStateAndResultAsync( + (ADUC_WorkflowDataToken)&tmpWorkflowData, deploymentState, &result, NULL /* installedUpdateId */); + if (!reportingSuccess) + { + goto done; + } + + // Set the last deployment state on the actual workflow data for correct handling of update action. + ADUC_WorkflowData_SetLastReportedState(deploymentState, workflowData); + + reportingSuccess = true; +done: + + if (tmpWorkflowData.WorkflowHandle != NULL) + { + // propertyValueCopy will get freed by workflow_free + workflow_free(tmpWorkflowData.WorkflowHandle); + } + + return reportingSuccess; +} + /** * @brief Callback for the orchestrator that allows the new patches coming down from the cloud to be organized * @param clientHandle the client handle being used for the connection @@ -330,8 +397,18 @@ void OrchestratorUpdateCallback( { UNREFERENCED_PARAMETER(clientHandle); + ADUC_Result tmpResult = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; ADUC_WorkflowData* workflowData = (ADUC_WorkflowData*)context; + STRING_HANDLE jsonToSend = NULL; + char* ackString = NULL; + JSON_Object* signatureObj = NULL; + + ADUCITF_UpdateAction updateAction = ADUCITF_UpdateAction_Undefined; + char* workflowId = NULL; + char* rootKeyPkgUrl = NULL; + STRING_HANDLE rootKeyPackageFilePath = NULL; + char* workFolder = NULL; // Reads out the json string so we can Log Out what we've got. // The value will be parsed and handled in ADUC_Workflow_HandlePropertyUpdate. @@ -345,8 +422,7 @@ void OrchestratorUpdateCallback( } // To reduce TWIN size, remove UpdateManifestSignature and fileUrls before ACK. - char* ackString = NULL; - JSON_Object* signatureObj = json_value_get_object(propertyValue); + signatureObj = json_value_get_object(propertyValue); if (signatureObj != NULL) { json_object_set_null(signatureObj, "updateManifestSignature"); @@ -356,6 +432,47 @@ void OrchestratorUpdateCallback( Log_Debug("Update Action info string (%s), property version (%d)", ackString, propertyVersion); + tmpResult = workflow_parse_peek_unprotected_workflow_properties( + json_object(propertyValue), &updateAction, &rootKeyPkgUrl, &workflowId); + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + Log_Error("Parse failed for unprotected properties, erc: 0x%08x", tmpResult.ExtendedResultCode); + // Note, cannot report failure here since workflowId from unprotected properties is needed for that. + goto done; + } + + if (updateAction == ADUCITF_UpdateAction_ProcessDeployment && !IsNullOrEmpty(workflowId)) + { + Log_Debug("Processing deployment %s ...", workflowId); + + ADUC_Result inProgressResult = { .ResultCode = ADUC_GeneralResult_Success, .ExtendedResultCode = 0 }; + if (!ReportPreDeploymentProcessingState(propertyValue, ADUCITF_State_DeploymentInProgress, workflowData, inProgressResult)) + { + Log_Warn("Reporting InProgress failed. Continuing processing deployment %s", workflowId); + } + + // Ensure update to latest rootkey pkg, which is required for validating the update metadata. + workFolder = workflow_get_workfolder(workflowData->WorkflowHandle); + if (workFolder == NULL) + { + Log_Error("workflow_get_workfolder failed."); + goto done; + } + + tmpResult = RootKeyWorkflow_UpdateRootKeys(workflowId, workFolder, rootKeyPkgUrl); + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + Log_Error("Update Rootkey failed, 0x%08x. Deployment cannot proceed.", tmpResult.ExtendedResultCode); + + if (!ReportPreDeploymentProcessingState(propertyValue, ADUCITF_State_Failed, workflowData, tmpResult)) + { + Log_Warn("FAIL: report rootkey update 'Failed' State."); + } + + goto done; + } + } + ADUC_Workflow_HandlePropertyUpdate(workflowData, (const unsigned char*)jsonString, sourceContext->forceUpdate); free(jsonString); jsonString = ackString; @@ -389,8 +506,11 @@ void OrchestratorUpdateCallback( } done: + STRING_delete(rootKeyPackageFilePath); + workflow_free_string(rootKeyPkgUrl); + workflow_free_string(workflowId); + workflow_free_string(workFolder); STRING_delete(jsonToSend); - free(jsonString); Log_Info("OrchestratorPropertyUpdateCallback ended"); @@ -428,7 +548,7 @@ void AzureDeviceUpdateCoreInterface_PropertyUpdateCallback( // Reporting // static JSON_Status _json_object_set_update_result( - JSON_Object* object, int32_t resultCode, int32_t extendedResultCode, const char* resultDetails) + JSON_Object* object, int32_t resultCode, STRING_HANDLE extendedResultCodes, const char* resultDetails) { JSON_Status status = json_object_set_number(object, ADUCITF_FIELDNAME_RESULTCODE, resultCode); if (status != JSONSuccess) @@ -437,10 +557,10 @@ static JSON_Status _json_object_set_update_result( goto done; } - status = json_object_set_number(object, ADUCITF_FIELDNAME_EXTENDEDRESULTCODE, extendedResultCode); + status = json_object_set_string(object, ADUCITF_FIELDNAME_EXTENDEDRESULTCODES, STRING_c_str(extendedResultCodes)); if (status != JSONSuccess) { - Log_Error("Could not set value for field: %s", ADUCITF_FIELDNAME_EXTENDEDRESULTCODE); + Log_Error("Could not set value for field: %s", ADUCITF_FIELDNAME_EXTENDEDRESULTCODES); goto done; } @@ -508,6 +628,21 @@ static bool set_workflow_properties( return succeeded; } +static STRING_HANDLE construct_extended_result_codes_str(ADUC_WorkflowHandle handle, ADUC_Result rootResult) +{ + STRING_HANDLE root_result_erc_str = + ADUC_ReportingUtils_CreateReportingErcHexStr(rootResult.ExtendedResultCode, true /* is_first */); + STRING_HANDLE extra_ercs_str = workflow_get_extra_ercs(handle); + if (extra_ercs_str != NULL && STRING_length(extra_ercs_str) > 0 && root_result_erc_str != NULL + && STRING_length(root_result_erc_str) > 0) + { + STRING_concat_with_STRING(root_result_erc_str, extra_ercs_str); + } + + STRING_delete(extra_ercs_str); + return root_result_erc_str; +} + /** * @brief Get the Reporting Json Value object * @@ -525,6 +660,13 @@ JSON_Value* GetReportingJsonValue( { JSON_Value* resultValue = NULL; + // Declare and init here to avoid maybe-uninitialized static analysis errors + JSON_Value* rootValue = NULL; + JSON_Value* lastInstallResultValue = NULL; + JSON_Value* stepResultsValue = NULL; + JSON_Value* workflowValue = NULL; + STRING_HANDLE rootResultERCs = NULL; + // // Get result from current workflow if exists. // (Note: on startup, update workflow is not started, unless there is an existing Update Action in the twin.) @@ -535,7 +677,6 @@ JSON_Value* GetReportingJsonValue( // ADUC_Result rootResult; ADUC_WorkflowHandle handle = workflowData->WorkflowHandle; - ADUC_Result_t successErc = workflow_get_success_erc(handle); if (result != NULL) { @@ -546,14 +687,16 @@ JSON_Value* GetReportingJsonValue( rootResult = workflow_get_result(handle); } - // Allow reporting of extended result code of soft-failing mechanisms, such as download handler, that have a - // fallback mechanism (e.g. full content download) that can ultimately become an overall success. - if (IsAducResultCodeSuccess(rootResult.ResultCode) && successErc != 0) + // The "extendedResultCodes" reported property is a JSON string, where the first ERC (8 hex digits) is always + // from the rootResult. Extra ERC can be appended for soft-failing mechanisms with fallback mechanisms + // e.g. download handler or update metadata rootkey management. + rootResultERCs = construct_extended_result_codes_str(handle, rootResult); + if (rootResultERCs == NULL) { - rootResult.ExtendedResultCode = successErc; + goto done; } - JSON_Value* rootValue = json_value_init_object(); + rootValue = json_value_init_object(); JSON_Object* rootObject = json_value_get_object(rootValue); size_t stepsCount = workflow_get_children_count(handle); @@ -572,31 +715,31 @@ JSON_Value* GetReportingJsonValue( // // "lastInstallResult" : { // "resultCode" : ####, - // "extendedResultCode" : ####, + // "extendedResultCodes" : "########,########", // "resultDetails" : "...", // "stepResults" : { // "step_0" : { // "resultCode" : ####, - // "extendedResultCode" : ####, + // "extendedResultCodes" : "########", // "resultDetails" : "..." // }, // ... // "step_N" : { // "resultCode" : ####, - // "extendedResultCode" : ####, + // "extendedResultCodes" : "########", // "resultDetails" : "..." // } // } // } // } - JSON_Value* lastInstallResultValue = json_value_init_object(); + lastInstallResultValue = json_value_init_object(); JSON_Object* lastInstallResultObject = json_object(lastInstallResultValue); - JSON_Value* stepResultsValue = json_value_init_object(); + stepResultsValue = json_value_init_object(); JSON_Object* stepResultsObject = json_object(stepResultsValue); - JSON_Value* workflowValue = json_value_init_object(); + workflowValue = json_value_init_object(); if (lastInstallResultValue == NULL || stepResultsValue == NULL || workflowValue == NULL) { @@ -690,10 +833,7 @@ JSON_Value* GetReportingJsonValue( // Set top-level update state and result. jsonStatus = _json_object_set_update_result( - lastInstallResultObject, - rootResult.ResultCode, - rootResult.ExtendedResultCode, - workflow_peek_result_details(handle)); + lastInstallResultObject, rootResult.ResultCode, rootResultERCs, workflow_peek_result_details(handle)); if (jsonStatus != JSONSuccess) { @@ -711,6 +851,7 @@ JSON_Value* GetReportingJsonValue( JSON_Value* childResultValue = NULL; JSON_Object* childResultObject = NULL; STRING_HANDLE childUpdateId = NULL; + STRING_HANDLE childExtendedResultCodes = NULL; if (childHandle == NULL) { @@ -745,10 +886,12 @@ JSON_Value* GetReportingJsonValue( } childResultValue = NULL; // stepResultsValue owns it now. + childExtendedResultCodes = + ADUC_ReportingUtils_CreateReportingErcHexStr(childResult.ExtendedResultCode, true /* is_first */); jsonStatus = _json_object_set_update_result( childResultObject, childResult.ResultCode, - childResult.ExtendedResultCode, + childExtendedResultCodes, workflow_peek_result_details(childHandle)); if (jsonStatus != JSONSuccess) @@ -758,6 +901,7 @@ JSON_Value* GetReportingJsonValue( childDone: STRING_delete(childUpdateId); + STRING_delete(childExtendedResultCodes); childUpdateId = NULL; json_value_free(childResultValue); childResultValue = NULL; @@ -772,6 +916,7 @@ JSON_Value* GetReportingJsonValue( json_value_free(lastInstallResultValue); json_value_free(stepResultsValue); json_value_free(workflowValue); + STRING_delete(rootResultERCs); return resultValue; } diff --git a/src/agent/adu_core_interface/src/device_properties.c b/src/agent/adu_core_interface/src/device_properties.c index f7cf4b326..31dd2ffe5 100644 --- a/src/agent/adu_core_interface/src/device_properties.c +++ b/src/agent/adu_core_interface/src/device_properties.c @@ -15,7 +15,7 @@ /** * @brief The ADU contract model id associated with the modelId for agent-orchestrated updates. */ -#define ADUC_DEVICEPROPERTIES_DEVICEUPDATE_CONTRACT_MODEL_ID "dtmi:azure:iot:deviceUpdateContractModel;2" +#define ADUC_DEVICEPROPERTIES_DEVICEUPDATE_CONTRACT_MODEL_ID "dtmi:azure:iot:deviceUpdateContractModel;3" /** @brief The adu client builder and version. * Consisting of BUILDER; component and ADUC_VERSION diff --git a/src/agent_orchestration/src/agent_orchestration.c b/src/agent_orchestration/src/agent_orchestration.c index 22d68b043..6f121b8a4 100644 --- a/src/agent_orchestration/src/agent_orchestration.c +++ b/src/agent_orchestration/src/agent_orchestration.c @@ -22,7 +22,8 @@ ADUCITF_WorkflowStep AgentOrchestration_GetWorkflowStep(const ADUCITF_UpdateActi switch (desiredUpdateAction) { case ADUCITF_UpdateAction_ProcessDeployment: - return ADUCITF_WorkflowStep_ProcessDeployment; + // DeploymentInProgress message already sent so start with download. + return ADUCITF_WorkflowStep_Download; case ADUCITF_UpdateAction_Cancel: // Should not get here as Cancel should have just signaled the cancel request diff --git a/src/communication_abstraction/CMakeLists.txt b/src/communication_abstraction/CMakeLists.txt index 559b8feb2..ef56b50a4 100644 --- a/src/communication_abstraction/CMakeLists.txt +++ b/src/communication_abstraction/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required (VERSION 3.5) +include (agentRules) + set (target_name communication_abstraction) add_library (${target_name} STATIC src/client_handle_helper.c) @@ -14,7 +16,7 @@ target_include_directories (${target_name} PUBLIC inc) # NOTE: the call to find_package for azure_c_shared_utility # must come before umqtt since their config.cmake files expect the aziotsharedutil target to already have been defined. -find_package (azure_c_shared_utility REQUIRED) +target_link_aziotsharedutil (${target_name} PRIVATE) find_package (IotHubClient REQUIRED) find_package (umqtt REQUIRED) diff --git a/src/communication_managers/iothub_communication_manager/CMakeLists.txt b/src/communication_managers/iothub_communication_manager/CMakeLists.txt index 3f0eda17a..9707b0692 100644 --- a/src/communication_managers/iothub_communication_manager/CMakeLists.txt +++ b/src/communication_managers/iothub_communication_manager/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required (VERSION 3.5) +include (agentRules) + set (target_name iothub_communication_manager) + add_library (${target_name} STATIC src/iothub_communication_manager.c) add_library (aduc::${target_name} ALIAS ${target_name}) @@ -12,7 +15,8 @@ target_include_directories (${target_name} PUBLIC ./inc ${ADUC_TYPES_INCLUDES} # set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) -find_package (azure_c_shared_utility REQUIRED) +target_link_aziotsharedutil (${target_name} PRIVATE) + find_package (umqtt REQUIRED) target_link_libraries ( @@ -23,9 +27,9 @@ target_link_libraries ( aduc::config_utils aduc::c_utils aduc::eis_utils - aduc::https_proxy_utils aduc::logging - aduc::retry_utils) + aduc::retry_utils + aduc::url_utils) target_link_libraries (${target_name} PRIVATE libaducpal) @@ -51,8 +55,5 @@ else () ) endif () -target_compile_definitions ( - ${target_name} - PRIVATE ADUC_AGENT_FILEPATH="${ADUC_AGENT_FILEPATH}" - ADUC_CONF_FILE_PATH="${ADUC_CONF_FILE_PATH}" -) +target_compile_definitions (${target_name} PRIVATE ADUC_AGENT_FILEPATH="${ADUC_AGENT_FILEPATH}" + ADUC_CONF_FILE_PATH="${ADUC_CONF_FILE_PATH}") diff --git a/src/communication_managers/iothub_communication_manager/src/iothub_communication_manager.c b/src/communication_managers/iothub_communication_manager/src/iothub_communication_manager.c index a0652f2fe..6397fea1c 100644 --- a/src/communication_managers/iothub_communication_manager/src/iothub_communication_manager.c +++ b/src/communication_managers/iothub_communication_manager/src/iothub_communication_manager.c @@ -81,7 +81,7 @@ static const OPTION_OPENSSL_KEY_TYPE x509_key_from_engine = KEY_TYPE_ENGINE; * * Customers should change this ID to match their device model ID. */ -static const char g_aduModelId[] = "dtmi:azure:iot:deviceUpdateModel;2"; +static const char g_aduModelId[] = "dtmi:azure:iot:deviceUpdateModel;3"; /** * @brief Current connection status. diff --git a/src/diagnostics_component/utils/file_info_utils/tests/CMakeLists.txt b/src/diagnostics_component/utils/file_info_utils/tests/CMakeLists.txt index a737aab21..239b9f330 100644 --- a/src/diagnostics_component/utils/file_info_utils/tests/CMakeLists.txt +++ b/src/diagnostics_component/utils/file_info_utils/tests/CMakeLists.txt @@ -15,6 +15,11 @@ add_executable (${PROJECT_NAME} ${sources}) target_link_aziotsharedutil (${PROJECT_NAME} PRIVATE) +# Windows needs all EXEs to have links to all potential libraries so this is included here +if (WIN32) + target_link_dosdk (${PROJECT_NAME} PRIVATE) +endif () + target_link_libraries ( ${PROJECT_NAME} PRIVATE aduc::jws_utils aduc::crypto_utils aduc::string_utils diagnostic_utils::file_info_utils Catch2::Catch2) diff --git a/src/diagnostics_component/utils/file_upload_utils/CMakeLists.txt b/src/diagnostics_component/utils/file_upload_utils/CMakeLists.txt index 7ec97cf5d..28390d22f 100644 --- a/src/diagnostics_component/utils/file_upload_utils/CMakeLists.txt +++ b/src/diagnostics_component/utils/file_upload_utils/CMakeLists.txt @@ -1,12 +1,15 @@ cmake_minimum_required (VERSION 3.13) +include (agentRules) + set (target_name file_upload_utility) add_library (${target_name} STATIC src/file_upload_utility.cpp src/blob_storage_helper.cpp src/blob_storage_helper.hpp) add_library (diagnostic_utils::${target_name} ALIAS ${target_name}) -find_package (azure_c_shared_utility REQUIRED) +target_link_aziotsharedutil (${target_name} PUBLIC) + find_package (azure-storage-blobs-cpp CONFIG REQUIRED) include (agentRules) @@ -17,7 +20,5 @@ find_curl_and_import_libcurl () target_include_directories (${target_name} PUBLIC inc) -target_link_libraries ( - ${target_name} - PUBLIC aziotsharedutil - PRIVATE aduc::c_utils aduc::exception_utils Azure::azure-storage-blobs CURL::libcurl) +target_link_libraries (${target_name} PRIVATE aduc::c_utils aduc::exception_utils + Azure::azure-storage-blobs CURL::libcurl) diff --git a/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/handler/lib/src/microsoft_delta_download_handler.c b/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/handler/lib/src/microsoft_delta_download_handler.c index 104f92b3e..1c9270096 100644 --- a/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/handler/lib/src/microsoft_delta_download_handler.c +++ b/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/handler/lib/src/microsoft_delta_download_handler.c @@ -82,7 +82,7 @@ ADUC_Result MicrosoftDeltaDownloadHandler_ProcessUpdate( if (relatedFileResult.ResultCode == ADUC_Result_Success_Cache_Miss) { Log_Warn("src update cache miss for Delta %d", index); - workflow_set_success_erc(workflowHandle, ADUC_ERC_DDH_SOURCE_UPDATE_CACHE_MISS); + workflow_add_erc(workflowHandle, ADUC_ERC_DDH_SOURCE_UPDATE_CACHE_MISS); continue; } @@ -94,7 +94,7 @@ ADUC_Result MicrosoftDeltaDownloadHandler_ProcessUpdate( } Log_Warn("Delta %d failed, ERC: 0x%08x.", index, relatedFileResult.ExtendedResultCode); - workflow_set_success_erc(workflowHandle, relatedFileResult.ExtendedResultCode); + workflow_add_erc(workflowHandle, relatedFileResult.ExtendedResultCode); // continue processing the next relatedFile } diff --git a/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/source_update_cache/CMakeLists.txt b/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/source_update_cache/CMakeLists.txt index 411de5413..371898fca 100644 --- a/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/source_update_cache/CMakeLists.txt +++ b/src/extensions/download_handlers/plugin_examples/microsoft_delta_download_handler/source_update_cache/CMakeLists.txt @@ -22,16 +22,13 @@ target_sources (${target_name} PRIVATE src/source_update_cache.c src/source_upda # set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) +target_link_aziotsharedutil (${target_name} PRIVATE) + target_link_libraries ( ${target_name} PUBLIC aduc::adu_types aduc::c_utils - PRIVATE aduc::file_utils - aduc::parser_utils - aduc::path_utils - aduc::permission_utils - aduc::system_utils - aduc::workflow_utils - aziotsharedutil) + PRIVATE aduc::file_utils aduc::parser_utils aduc::path_utils aduc::permission_utils + aduc::system_utils aduc::workflow_utils) target_compile_definitions ( ${target_name} diff --git a/src/extensions/extension_manager/src/extension_manager.cpp b/src/extensions/extension_manager/src/extension_manager.cpp index c6bbfc63b..fba834eb6 100644 --- a/src/extensions/extension_manager/src/extension_manager.cpp +++ b/src/extensions/extension_manager/src/extension_manager.cpp @@ -966,8 +966,8 @@ ADUC_Result ExtensionManager::Download( result.ResultCode = ADUC_Result_Failure; result.ExtendedResultCode = ADUC_ERC_CONTENT_DOWNLOADER_INVALID_FILE_HASH; - workflow_set_success_erc(workflowHandle, result.ExtendedResultCode); Log_Error("Successful download of '%s' failed hash check.", targetUpdateFilePath.c_str()); + workflow_add_erc(workflowHandle, result.ExtendedResultCode); goto done; } diff --git a/src/extensions/extension_manager/src/extension_manager_helper.cpp b/src/extensions/extension_manager/src/extension_manager_helper.cpp index a307d149e..b15b66a23 100644 --- a/src/extensions/extension_manager/src/extension_manager_helper.cpp +++ b/src/extensions/extension_manager/src/extension_manager_helper.cpp @@ -61,7 +61,7 @@ ADUC_Result ProcessDownloadHandlerExtensibility( result.ExtendedResultCode = ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_CREATE_FAILURE_CREATE; - workflow_set_success_erc(workflowHandle, ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_CREATE_FAILURE_CREATE); + workflow_add_erc(workflowHandle, ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_CREATE_FAILURE_CREATE); goto done; } @@ -77,7 +77,7 @@ ADUC_Result ProcessDownloadHandlerExtensibility( result.ResultCode, result.ExtendedResultCode); - workflow_set_success_erc(workflowHandle, ADUC_ERC_DOWNLOAD_HANDLER_EXTENSIBILITY_GET_CONTRACT); + workflow_add_erc(workflowHandle, ADUC_ERC_DOWNLOAD_HANDLER_EXTENSIBILITY_GET_CONTRACT); goto done; } @@ -95,7 +95,7 @@ ADUC_Result ProcessDownloadHandlerExtensibility( result.ResultCode = ADUC_GeneralResult_Failure; result.ExtendedResultCode = ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_UNSUPPORTED_CONTRACT_VERSION; - workflow_set_success_erc( + workflow_add_erc( workflowHandle, ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_UNSUPPORTED_CONTRACT_VERSION); goto done; @@ -106,7 +106,7 @@ ADUC_Result ProcessDownloadHandlerExtensibility( result = plugin->ProcessUpdate(workflowHandle, entity, targetUpdateFilePath); if (IsAducResultCodeFailure(result.ResultCode)) { - workflow_set_success_erc(workflowHandle, result.ExtendedResultCode); + workflow_add_erc(workflowHandle, result.ExtendedResultCode); workflow_set_result_details(workflowHandle, "plugin err %d for ProcessUpdate", result.ExtendedResultCode); goto done; } diff --git a/src/extensions/extension_manager/tests/CMakeLists.txt b/src/extensions/extension_manager/tests/CMakeLists.txt index a1c92c730..ab322049c 100644 --- a/src/extensions/extension_manager/tests/CMakeLists.txt +++ b/src/extensions/extension_manager/tests/CMakeLists.txt @@ -27,6 +27,11 @@ target_link_libraries ( Catch2::Catch2 Parson::parson) +# Windows needs all EXEs to have links to all potential libraries so this is included here +if (WIN32) + target_link_dosdk (${target_name} PRIVATE) +endif () + target_link_libraries (${target_name} PRIVATE libaducpal) target_compile_definitions (${target_name} PRIVATE ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}") diff --git a/src/extensions/step_handlers/script_handler/CMakeLists.txt b/src/extensions/step_handlers/script_handler/CMakeLists.txt index f411d4257..15c69665d 100644 --- a/src/extensions/step_handlers/script_handler/CMakeLists.txt +++ b/src/extensions/step_handlers/script_handler/CMakeLists.txt @@ -29,6 +29,13 @@ target_link_libraries ( target_link_libraries (${target_name} PUBLIC libaducpal) +# Windows needs all DLLS to have links to all potential libraries so this is included here +if (WIN32) + + target_link_dosdk (${target_name} PRIVATE) + +endif () + target_compile_definitions (${target_name} PRIVATE ADUSHELL_FILE_PATH="${ADUSHELL_FILE_PATH}") install (TARGETS ${target_name} LIBRARY DESTINATION ${ADUC_EXTENSIONS_INSTALL_FOLDER}) diff --git a/src/extensions/step_handlers/script_handler/tests/CMakeLists.txt b/src/extensions/step_handlers/script_handler/tests/CMakeLists.txt index 85683cfcb..e3fde9476 100644 --- a/src/extensions/step_handlers/script_handler/tests/CMakeLists.txt +++ b/src/extensions/step_handlers/script_handler/tests/CMakeLists.txt @@ -7,21 +7,21 @@ include (agentRules) compileasc99 () disablertti () -set ( - sources - main.cpp - script_handler_ut.cpp - ../src/script_handler.cpp - ../../../update_manifest_handlers/steps_handler/src/steps_handler.cpp) +set (sources main.cpp script_handler_ut.cpp ../src/script_handler.cpp + ../../../update_manifest_handlers/steps_handler/src/steps_handler.cpp) add_executable (${PROJECT_NAME} ${sources}) target_link_aziotsharedutil (${PROJECT_NAME} PRIVATE) +# Windows needs all EXEs to have links to all potential libraries so this is included here +if (WIN32) + target_link_dosdk (${PROJECT_NAME} PRIVATE) +endif () + find_package (Catch2 REQUIRED) find_package (IotHubClient REQUIRED) find_package (umqtt REQUIRED) - target_include_directories ( ${PROJECT_NAME} PUBLIC inc @@ -49,7 +49,9 @@ target_link_libraries ( target_link_libraries (${PROJECT_NAME} PRIVATE libaducpal) -target_compile_definitions (${PROJECT_NAME} PRIVATE ADUSHELL_FILE_PATH="${ADUSHELL_FILE_PATH}" ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}") +target_compile_definitions ( + ${PROJECT_NAME} PRIVATE ADUSHELL_FILE_PATH="${ADUSHELL_FILE_PATH}" + ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}") include (CTest) include (Catch) diff --git a/src/extensions/step_handlers/simulator_handler/CMakeLists.txt b/src/extensions/step_handlers/simulator_handler/CMakeLists.txt index 583b3cb0c..af3697083 100644 --- a/src/extensions/step_handlers/simulator_handler/CMakeLists.txt +++ b/src/extensions/step_handlers/simulator_handler/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required (VERSION 3.5) +include (agentRules) set (target_name microsoft_simulator_1) @@ -31,6 +32,8 @@ target_link_libraries (${target_name} PRIVATE libaducpal) target_link_aziotsharedutil (${target_name} PRIVATE) +target_link_dosdk (${target_name} PRIVATE) + install (TARGETS ${target_name} LIBRARY DESTINATION ${ADUC_EXTENSIONS_INSTALL_FOLDER}) if (ADUC_BUILD_UNIT_TESTS) diff --git a/src/extensions/step_handlers/simulator_handler/tests/CMakeLists.txt b/src/extensions/step_handlers/simulator_handler/tests/CMakeLists.txt index aee0ebd83..9fb8ccc80 100644 --- a/src/extensions/step_handlers/simulator_handler/tests/CMakeLists.txt +++ b/src/extensions/step_handlers/simulator_handler/tests/CMakeLists.txt @@ -17,12 +17,8 @@ add_executable (${PROJECT_NAME} ${sources}) target_include_directories ( ${PROJECT_NAME} - PRIVATE ${ADUC_EXPORT_INCLUDES} - ${ADU_EXTENSION_INCLUDES} - ${ADU_SHELL_INCLUDES} - ${PROJECT_SOURCE_DIR}/inc - ${PROJECT_SOURCE_DIR}/../inc - ${PROJECT_SOURCE_DIR}/../../inc) + PRIVATE ${ADUC_EXPORT_INCLUDES} ${ADU_EXTENSION_INCLUDES} ${ADU_SHELL_INCLUDES} + ${PROJECT_SOURCE_DIR}/inc ${PROJECT_SOURCE_DIR}/../inc ${PROJECT_SOURCE_DIR}/../../inc) target_link_libraries ( ${PROJECT_NAME} @@ -39,6 +35,11 @@ target_link_libraries ( aduc::workflow_utils Parson::parson) +# Windows needs all EXEs to have links to all potential libraries so this is included here +if (WIN32) + target_link_dosdk (${PROJECT_NAME} PRIVATE) +endif () + target_link_libraries (${PROJECT_NAME} PRIVATE libaducpal) # Ensure that ctest discovers catch2 tests. diff --git a/src/extensions/step_handlers/wim_handler/CMakeLists.txt b/src/extensions/step_handlers/wim_handler/CMakeLists.txt index a530e3885..0fe7a3dff 100644 --- a/src/extensions/step_handlers/wim_handler/CMakeLists.txt +++ b/src/extensions/step_handlers/wim_handler/CMakeLists.txt @@ -22,6 +22,13 @@ target_include_directories ( target_link_aziotsharedutil (${target_name} PRIVATE) +# Windows needs all DLLS to have links to all potential libraries so this is included here +if (WIN32) + + target_link_dosdk (${target_name} PRIVATE) + +endif () + target_link_libraries ( ${target_name} PRIVATE aduc::c_utils diff --git a/src/extensions/update_manifest_handlers/steps_handler/CMakeLists.txt b/src/extensions/update_manifest_handlers/steps_handler/CMakeLists.txt index 26c419e74..789852ece 100644 --- a/src/extensions/update_manifest_handlers/steps_handler/CMakeLists.txt +++ b/src/extensions/update_manifest_handlers/steps_handler/CMakeLists.txt @@ -18,21 +18,22 @@ target_sources (${target_name} PRIVATE src/steps_handler.cpp src/handler_create. target_include_directories ( ${target_name} PUBLIC inc - PRIVATE ${PROJECT_SOURCE_DIR}/inc - ${ADUC_TYPES_INCLUDES} - ${ADUC_EXPORT_INCLUDES} - ${ADU_SHELL_INCLUDES} - ${ADU_EXTENSION_INCLUDES}) - -get_filename_component ( - ADUC_INSTALLEDCRITERIA_FILE_PATH - "${ADUC_DATA_FOLDER}/${ADUC_INSTALLEDCRITERIA_FILE}" - ABSOLUTE - "/") + PRIVATE ${PROJECT_SOURCE_DIR}/inc ${ADUC_TYPES_INCLUDES} ${ADUC_EXPORT_INCLUDES} + ${ADU_SHELL_INCLUDES} ${ADU_EXTENSION_INCLUDES}) + +get_filename_component (ADUC_INSTALLEDCRITERIA_FILE_PATH + "${ADUC_DATA_FOLDER}/${ADUC_INSTALLEDCRITERIA_FILE}" ABSOLUTE "/") target_compile_definitions ( ${target_name} PRIVATE ADUC_INSTALLEDCRITERIA_FILE_PATH="${ADUC_INSTALLEDCRITERIA_FILE_PATH}") +# Windows needs all DLLS to have links to all potential libraries so this is included here +if (WIN32) + + target_link_dosdk (${target_name} PRIVATE) + +endif () + target_link_libraries ( ${target_name} PRIVATE aduc::agent_workflow diff --git a/src/inc/aduc/result.h b/src/inc/aduc/result.h index bfa51c112..1c23e16e4 100644 --- a/src/inc/aduc/result.h +++ b/src/inc/aduc/result.h @@ -95,7 +95,8 @@ typedef enum tagADUC_Facility ADUC_FACILITY_UTILITY = 8, //!< ADUC_FACILITY_UTILITY : 8, indicates errors from utility functions. ADUC_FACILITY_DOWNLOAD_HANDLER = 9, //!< ADUC_FACILITY_DOWNLOAD_HANDLER : 9, Indicates errors from download handler infrastructure or download handler extensions. - ADUC_FACILITY_UNUSED_A = 10, //!< ADUC_FACILITY_UNUSED_A : 10, unused + ADUC_FACILITY_INFRA_MGMT = + 10, //!< ADUC_FACILITY_INFRA_MGMT : 10, Indicates extended result codes for infrastructure management needed for proper functioning/integrity of update deployments. ADUC_FACILITY_UNUSED_B = 11, //!< ADUC_FACILITY_UNUSED_B : 11, unused ADUC_FACILITY_UNUSED_C = 12, //!< ADUC_FACILITY_UNUSED_C : 12, unused ADUC_FACILITY_DELIVERY_OPTIMIZATION = @@ -109,6 +110,8 @@ typedef enum tagADUC_FACILITY_UNKNOWN_Components ERRNO = 0, //!< ERRNO : 0, General Error Codes, that come from POSIX 2001 Standard Errnos ADUC_COMPONENT_CRYPTO = 1, //!< ADUC_COMPONENT_CRYPTO : 1, validation and cryptographic component ADUC_COMPONENT_PLUGIN_CALL = 2, //!< ADUC_COMPONENT_PLUGIN_CALL : 2, plugin call helper component + ADUC_COMPONENT_COMMON_ERRORS = + 3, //!< ADUC_COMPONENT_COMMON_ERRORS : 3, Errors that are common across the codebase but are not ERRNO errors } ADUC_FACILITY_UNKNOWN_Components; typedef enum tagADUC_FACILITY_LOWERLAYER_Components @@ -161,6 +164,11 @@ typedef enum tagADUC_FACILITY_UTILITY_Components ADUC_COMPONENT_UPDATE_DATA_PARSER = 3, //!< ADUC_COMPONENT_UPDATE_DATA_PARSER : 3, indicates errors from parsers. ADUC_COMPONENT_WORKFLOW_UTIL = 4, //!< ADUC_COMPONENT_WORKFLOW_UTIL : 4, indicates errors from Workflow Utilities or Function. + ADUC_COMPONENT_ROOTKEYPKG_UTIL = + 5, //!< ADUC_COMPONENT_ROOTKEYPKG_UTIL : 5, indicates errors from RootKeyPackage Utilities or Function. + ADUC_COMPONENT_ROOTKEY_UTIL = + 6, //!< ADUC_COMPONENT_ROOTKEY_UTIL : 6, indicates errors from RootKey Utilities or function + ADUC_COMPONENT_URL_UTIL = 7, //!< ADUC_COMPONENT_URL_UTIL : 7, indicates errors from url utility. } ADUC_FACILITY_UTILITY_Components; typedef enum tagADUC_FACILITY_DOWNLOAD_HANDLER_Components @@ -177,6 +185,16 @@ typedef enum tagADUC_FACILITY_DOWNLOAD_HANDLER_Components 10, //!< ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_DELTA_PROCESSOR : 10, error code for errors from delta processor API } ADUC_FACILITY_DOWNLOAD_HANDLER_Components; +typedef enum tagADUC_FACILITY_INFRA_MGMT_Components +{ + ADUC_COMPONENT_ROOTKEY_WORKFLOW = + 0, //!< ADUC_COMPONENT_ROOTKEY_WORKFLOW : 0, indicates extended result codes for root key workflow. + ADUC_COMPONENT_ROOTKEY_DOWNLOADER = + 1, //!< ADUC_COMPONENT_ROOTKEY_DOWNLOADER : 1, indicates extended result codes for repacking root key downloader ones. + ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION = + 2, //!< ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION : 2, indicates extended result codes to pack JWSResult during update manifest validation. +} ADUC_FACILITY_INFRA_MGMT_Components; + // // Extended Result Code Make Functions // @@ -213,6 +231,15 @@ static inline ADUC_Result_t MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMP return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNKNOWN(ADUC_COMPONENT_PLUGIN_CALL, value); } +/** +* @brief Function for generating Extended Result Codes for ADUC_COMPONENT_COMMON_ERRORS Component +*/ +static inline ADUC_Result_t +MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_COMMON_ERRORS(const int32_t value) +{ + return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNKNOWN(ADUC_COMPONENT_COMMON_ERRORS, value); +} + /** * @brief Extended Result Codes for ADUC_FACILITY_LOWERLAYER Facility */ @@ -435,6 +462,31 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_WORKFLOW_UTIL(const in return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UTILITY(ADUC_COMPONENT_WORKFLOW_UTIL, value); } +/** +* @brief Function for generating Extended Result Codes for ADUC_COMPONENT_ROOTKEYPKG_UTIL Component +*/ +static inline ADUC_Result_t +MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(const int32_t value) +{ + return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UTILITY(ADUC_COMPONENT_ROOTKEYPKG_UTIL, value); +} + +/** +* @brief Function for generating Extended Result Codes for ADUC_COMPONENT_ROOTKEY_UTIL Component +*/ +static inline ADUC_Result_t MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(const int32_t value) +{ + return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UTILITY(ADUC_COMPONENT_ROOTKEY_UTIL, value); +} + +/** +* @brief Function for generating Extended Result Codes for ADUC_COMPONENT_URL_UTIL Component +*/ +static inline ADUC_Result_t MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_URL_UTIL(const int32_t value) +{ + return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UTILITY(ADUC_COMPONENT_URL_UTIL, value); +} + /** * @brief Extended Result Codes for ADUC_FACILITY_DOWNLOAD_HANDLER Facility */ @@ -496,12 +548,41 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER } /** - * @brief Extended Result Codes for ADUC_FACILITY_UNUSED_A Facility + * @brief Extended Result Codes for ADUC_FACILITY_INFRA_MGMT Facility */ static inline ADUC_Result_t -MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNUSED_A(const int32_t component, const int32_t value) +MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_INFRA_MGMT(const int32_t component, const int32_t value) { - return MAKE_ADUC_EXTENDEDRESULTCODE(ADUC_FACILITY_UNUSED_A, component, value); + return MAKE_ADUC_EXTENDEDRESULTCODE(ADUC_FACILITY_INFRA_MGMT, component, value); +} + +/** +* @brief Function for generating Extended Result Codes for ADUC_COMPONENT_ROOTKEY_WORKFLOW Component +*/ +static inline ADUC_Result_t +MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(const int32_t value) +{ + return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_INFRA_MGMT(ADUC_COMPONENT_ROOTKEY_WORKFLOW, value); +} + +/** +* @brief Function for generating Extended Result Codes for ADUC_COMPONENT_ROOTKEY_DOWNLOADER Component +*/ +static inline ADUC_Result_t +MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_DOWNLOADER(const int32_t value) +{ + return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_INFRA_MGMT( + ADUC_COMPONENT_ROOTKEY_DOWNLOADER, value); +} + +/** +* @brief Function for generating Extended Result Codes for ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION Component +*/ +static inline ADUC_Result_t +MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION(const int32_t value) +{ + return MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_INFRA_MGMT( + ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION, value); } /** @@ -562,6 +643,11 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNUSED_F(const int32_t c */ #define ADUC_ERC_NOMEM MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ERRNO(12) +/** + * @brief ADUC_ERC_INVAL, ERC Value: 22 (0x16) + */ +#define ADUC_ERC_INVAL MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ERRNO(22) + /** * @brief ADUC_ERC_NOTRECOVERABLE, ERC Value: 131 (0x83) */ @@ -589,6 +675,11 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNUSED_F(const int32_t c #define ADUC_ERC_PLUGIN_CALL_RESOLVE_EXPORT_SYMBOL \ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_PLUGIN_CALL(1) +/** + * @brief ADUC_ERC_INVALIDARG, ERC Value: 3145729 (0x300001) + */ +#define ADUC_ERC_INVALIDARG MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_COMMON_ERRORS(1) + /** * @brief ADUC_ERC_LOWERLEVEL_INVALID_UPDATE_ACTION, ERC Value: 268435457 (0x10000001) */ @@ -1151,18 +1242,18 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNUSED_F(const int32_t c #define ADUC_ERC_STEPS_HANDLER_DOWNLOAD_UNKNOWN_EXCEPTION_DOWNLOAD_CONTENT \ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_CONTENT_HANDLER_STEPS(258) -/** - * @brief ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURES_UNKNOWNEXCEPTION, ERC Value: 809501184 (0x30400200) - */ -#define ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURES_UNKNOWNEXCEPTION \ - MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_CONTENT_HANDLER_STEPS(512) - /** * @brief ADUC_ERC_STEPS_HANDLER_ISINSTALLED_FAILURE_MISSING_CHILD_WORKFLOW, ERC Value: 809501173 (0x304001f5) */ #define ADUC_ERC_STEPS_HANDLER_ISINSTALLED_FAILURE_MISSING_CHILD_WORKFLOW \ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_CONTENT_HANDLER_STEPS(501) +/** + * @brief ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURES_UNKNOWNEXCEPTION, ERC Value: 809501184 (0x30400200) + */ +#define ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURES_UNKNOWNEXCEPTION \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_CONTENT_HANDLER_STEPS(512) + /** * @brief ADUC_ERC_STEPS_HANDLER_INSTALL_FAILURE_MISSING_CHILD_WORKFLOW, ERC Value: 809501185 (0x30400201) */ @@ -1552,6 +1643,30 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNUSED_F(const int32_t c #define ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_DOWNLOAD_FAILED \ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_UPDATE_DATA_PARSER(13) +/** + * @brief ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST_JSON_FILE, ERC Value: 2150629390 (0x8030000e) + */ +#define ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST_JSON_FILE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_UPDATE_DATA_PARSER(14) + +/** + * @brief ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_MISSING_UPDATEMANIFEST_PROPERTY, ERC Value: 2150629391 (0x8030000f) + */ +#define ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_MISSING_UPDATEMANIFEST_PROPERTY \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_UPDATE_DATA_PARSER(15) + +/** + * @brief ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_WORKFLOW_ACTION, ERC Value: 2150629392 (0x80300010) + */ +#define ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_WORKFLOW_ACTION \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_UPDATE_DATA_PARSER(16) + +/** + * @brief ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_EMPTY_OR_MISSING_ROOTKEY_PKG_URL, ERC Value: 2150629393 (0x80300011) + */ +#define ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_EMPTY_OR_MISSING_ROOTKEY_PKG_URL \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_UPDATE_DATA_PARSER(17) + /** * @brief ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM, ERC Value: 2151677953 (0x80400001) */ @@ -1630,6 +1745,350 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNUSED_F(const int32_t c #define ADUC_ERC_UTILITIES_WORKFLOW_UTIL_COPY_UPDATE_ACTION_COPY_HANDLER_PROPERTIES_FAILED \ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_WORKFLOW_UTIL(13) +/** + * @brief ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PROPERTYUPDATE_JSON_FILE, ERC Value: 2151677966 (0x8040000e) + */ +#define ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PROPERTYUPDATE_JSON_FILE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_WORKFLOW_UTIL(14) + +/** + * @brief ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PROPERTYUPDATE_JSON_STRING, ERC Value: 2151677967 (0x8040000f) + */ +#define ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PROPERTYUPDATE_JSON_STRING \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_WORKFLOW_UTIL(15) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_UNEXPECTED, ERC Value: 2152726529 (0x80500001) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_UNEXPECTED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(1) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG, ERC Value: 2152726530 (0x80500002) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(2) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_JSON, ERC Value: 2152726531 (0x80500003) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_JSON \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(3) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_VERSION, ERC Value: 2152726532 (0x80500004) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_VERSION \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(4) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PUBLISHED, ERC Value: 2152726533 (0x80500005) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PUBLISHED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(5) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDROOTKEYS, ERC Value: 2152726534 (0x80500006) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDROOTKEYS \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(6) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_HASHING_PROPERTY_ALG, ERC Value: 2152726535 (0x80500007) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_HASHING_PROPERTY_ALG \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(7) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_SIGNATURE_PROPERTY_ALG, ERC Value: 2152726536 (0x80500008) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_SIGNATURE_PROPERTY_ALG \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(8) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_HASH_OR_SIG, ERC Value: 2152726537 (0x80500009) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_HASH_OR_SIG \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(9) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDSIGNINGKEYS, ERC Value: 2152726538 (0x8050000a) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDSIGNINGKEYS \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(10) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_KEYTYPE, ERC Value: 2152726539 (0x8050000b) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_KEYTYPE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(11) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_ROOTKEYS, ERC Value: 2152726540 (0x8050000c) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_ROOTKEYS \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(12) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PROTECTED, ERC Value: 2152726541 (0x8050000d) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PROTECTED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(13) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_SIGNATURES, ERC Value: 2152726542 (0x8050000e) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_SIGNATURES \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(14) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_ROOTKEYS_EMPTY, ERC Value: 2152726545 (0x80500011) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_ROOTKEYS_EMPTY \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(17) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_SIGNATURES_EMPTY, ERC Value: 2152726546 (0x80500012) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_SIGNATURES_EMPTY \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(18) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_MODULUS, ERC Value: 2152726547 (0x80500013) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_MODULUS \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(19) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_HASH_ALGORITHM, ERC Value: 2152726548 (0x80500014) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_HASH_ALGORITHM \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(20) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_SIGNING_ALGORITHM, ERC Value: 2152726549 (0x80500015) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_SIGNING_ALGORITHM \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(21) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_ENCODING, ERC Value: 2152726550 (0x80500016) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_ENCODING \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(22) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_KEY_ID, ERC Value: 2152726551 (0x80500017) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_KEY_ID \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(23) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_UNSUPPORTED_KEYTYPE, ERC Value: 2152726552 (0x80500018) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_UNSUPPORTED_KEYTYPE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(24) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_RSA_PARAMETERS, ERC Value: 2152726553 (0x80500019) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_RSA_PARAMETERS \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(25) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_SIGNATURES_ELEMENT, ERC Value: 2152726554 (0x8050001a) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_SIGNATURES_ELEMENT \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(26) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_DISABLEDSIGNINGKEYS_ELEMENT, ERC Value: 2152726555 (0x8050001b) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_DISABLEDSIGNINGKEYS_ELEMENT \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(27) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_EXPONENT, ERC Value: 2152726556 (0x8050001c) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_EXPONENT \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(28) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_BADARG, ERC Value: 2152726557 (0x8050001d) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_BADARG \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(29) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_MKDIR_DWNLD_FOLDER, ERC Value: 2152726558 (0x8050001e) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_MKDIR_DWNLD_FOLDER \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(30) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_URL_BAD_PATH, ERC Value: 2152726559 (0x8050001f) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_URL_BAD_PATH \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEYPKG_UTIL(31) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_UNEXPECTED, ERC Value: 2153775105 (0x80600001) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_UNEXPECTED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(1) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_HARDCODED_ROOTKEY_LOAD_FAILED, ERC Value: 2153775106 (0x80600002) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_HARDCODED_ROOTKEY_LOAD_FAILED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(2) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_FOR_KEY_NOT_FOUND, ERC Value: 2153775107 (0x80600003) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_FOR_KEY_NOT_FOUND \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(3) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_VALIDATION_FAILED, ERC Value: 2153775108 (0x80600004) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_VALIDATION_FAILED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(4) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_STORE_FAILED, ERC Value: 2153775109 (0x80600005) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_STORE_FAILED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(5) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_BAD_ARGS, ERC Value: 2153775110 (0x80600006) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_BAD_ARGS \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(6) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANNOT_WRITE_PACKAGE_TO_STORE, ERC Value: 2153775111 (0x80600007) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANNOT_WRITE_PACKAGE_TO_STORE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(7) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_RENAME_TO_STORE, ERC Value: 2153775112 (0x80600008) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_RENAME_TO_STORE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(8) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_LOAD_FROM_STORE, ERC Value: 2153775113 (0x80600009) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_LOAD_FROM_STORE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(9) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_FAILED_SERIALIZE_TO_STRING, ERC Value: 2153775114 (0x8060000a) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_FAILED_SERIALIZE_TO_STRING \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(10) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_NO_ROOTKEY_FOUND_FOR_KEYID, ERC Value: 2153775115 (0x8060000b) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_NO_ROOTKEY_FOUND_FOR_KEYID \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(11) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERRNOMEM, ERC Value: 2153775116 (0x8060000c) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERRNOMEM \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(12) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_ROOTKEY_IS_DISABLED, ERC Value: 2153775117 (0x8060000d) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_ROOTKEY_IS_DISABLED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(13) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_MISSING_SIGNING_KEY, ERC Value: 2153775118 (0x8060000e) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_MISSING_SIGNING_KEY \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(14) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_LOCAL_STORE_UNINITIALIZED, ERC Value: 2153775119 (0x8060000f) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_LOCAL_STORE_UNINITIALIZED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(15) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_PAYLOAD_BAD_JSON, ERC Value: 2153775120 (0x80600010) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_PAYLOAD_BAD_JSON \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(16) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_KEY_TYPE, ERC Value: 2153775121 (0x80600011) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_KEY_TYPE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(17) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_ALG, ERC Value: 2153775122 (0x80600012) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_ALG \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(18) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_N, ERC Value: 2153775123 (0x80600013) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_N \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(19) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_EXPONENT, ERC Value: 2153775124 (0x80600014) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_KEY_INVALID_EXPONENT \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(20) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERR_GEN_PUBKEY, ERC Value: 2153775125 (0x80600015) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERR_GEN_PUBKEY \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(21) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERR_CREATE_HASH_PUBKEY, ERC Value: 2153775126 (0x80600016) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERR_CREATE_HASH_PUBKEY \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(22) + +/** + * @brief ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_DOWNLOAD_EXCEPTION, ERC Value: 2153775127 (0x80600017) + */ +#define ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_DOWNLOAD_EXCEPTION \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_UTIL(23) + +/** + * @brief ADUC_ERC_UTILITIES_URL_BAD_ARG, ERC Value: 2154823681 (0x80700001) + */ +#define ADUC_ERC_UTILITIES_URL_BAD_ARG MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_URL_UTIL(1) + +/** + * @brief ADUC_ERC_UTILITIES_URL_BAD_URL, ERC Value: 2154823682 (0x80700002) + */ +#define ADUC_ERC_UTILITIES_URL_BAD_URL MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_URL_UTIL(2) + +/** + * @brief ADUC_ERC_UTILITIES_URL_BAD_PATH, ERC Value: 2154823683 (0x80700003) + */ +#define ADUC_ERC_UTILITIES_URL_BAD_PATH MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_URL_UTIL(3) + +/** + * @brief ADUC_ERC_UTILITIES_URL_PATH_COPY, ERC Value: 2154823684 (0x80700004) + */ +#define ADUC_ERC_UTILITIES_URL_PATH_COPY MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_URL_UTIL(4) + /** * @brief ADUC_ERC_DOWNLOAD_HANDLER_EXTENSION_MANAGER_CREATE_FAILURE_CREATE, ERC Value: 2415919105 (0x90000001) */ @@ -1822,6 +2281,58 @@ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_UNUSED_F(const int32_t c #define ADUC_ERC_MISSING_SOURCE_SANDBOX_FILE \ MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_DELTA_DOWNLOAD_HANDLER_SOURCE_UPDATE_CACHE(7) +/** + * @brief ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_PARSE, ERC Value: 2684354561 (0xa0000001) + */ +#define ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_PARSE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(1) + +/** + * @brief ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_SERIALIZE, ERC Value: 2684354562 (0xa0000002) + */ +#define ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_SERIALIZE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(2) + +/** + * @brief ADUC_ERC_ROOTKEY_STORE_PATH_CREATE, ERC Value: 2684354563 (0xa0000003) + */ +#define ADUC_ERC_ROOTKEY_STORE_PATH_CREATE \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(3) + +/** + * @brief ADUC_ERC_ROOTKEY_SIGNINGKEY_DISABLE_EVAL_INVALID_HASHALG, ERC Value: 2684354564 (0xa0000004) + */ +#define ADUC_ERC_ROOTKEY_SIGNINGKEY_DISABLE_EVAL_INVALID_HASHALG \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(4) + +/** + * @brief ADUC_ERC_ROOTKEY_SIGNING_KEY_IS_DISABLED, ERC Value: 2684354565 (0xa0000005) + */ +#define ADUC_ERC_ROOTKEY_SIGNING_KEY_IS_DISABLED \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(5) + +/** + * @brief ADUC_ERC_ROOTKEY_PROD_PKG_ON_TEST_AGENT, ERC Value: 2684354566 (0xa0000006) + */ +#define ADUC_ERC_ROOTKEY_PROD_PKG_ON_TEST_AGENT \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(6) + +/** + * @brief ADUC_ERC_ROOTKEY_TEST_PKG_ON_PROD_AGENT, ERC Value: 2684354567 (0xa0000007) + */ +#define ADUC_ERC_ROOTKEY_TEST_PKG_ON_PROD_AGENT \ + MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(7) + +/** + * @brief ADUC_ERC_ROOTKEY_PACKAGE_CHANGED, ERC Value: 2684354568 (0xa0000008) + */ +#define ADUC_ERC_ROOTKEY_PACKAGE_CHANGED MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(8) + +/** + * @brief ADUC_ERC_ROOTKEY_PKG_UNCHANGED, ERC Value: 2684358655 (0xa0000fff) + */ +#define ADUC_ERC_ROOTKEY_PKG_UNCHANGED MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_COMPONENT_ROOTKEY_WORKFLOW(4095) + // // STATIC FUNCTIONS, NOT GENERATED BUT USE GENERATED FUNCTIONS // diff --git a/src/logging/inc/aduc/logging.h b/src/logging/inc/aduc/logging.h index 9bfd2f2c8..bab701a00 100644 --- a/src/logging/inc/aduc/logging.h +++ b/src/logging/inc/aduc/logging.h @@ -62,11 +62,6 @@ ADUC_LOG_SEVERITY ADUC_Logging_GetLevel(); */ # define Log_Error log_error -/* - * @brief Request a buffer flush. - */ -# define Log_RequestFlush zlog_request_flush_buffer - #elif ADUC_USE_XLOGGING # include diff --git a/src/logging/zlog/inc/zlog.h b/src/logging/zlog/inc/zlog.h index e2b962188..79c2fccd6 100644 --- a/src/logging/zlog/inc/zlog.h +++ b/src/logging/zlog/inc/zlog.h @@ -55,8 +55,6 @@ int zlog_init( void zlog_finish(void); // explicitly flush the buffer in memory void zlog_flush_buffer(void); -// request to flush the buffer. -void zlog_request_flush_buffer(void); // log an entry with the function scope and timestamp void zlog_log(enum ZLOG_SEVERITY msg_level, const char* func, unsigned int line, const char* fmt, ...); diff --git a/src/platform_layers/linux_platform_layer/tests/CMakeLists.txt b/src/platform_layers/linux_platform_layer/tests/CMakeLists.txt index 1d594565e..6cbf0617a 100644 --- a/src/platform_layers/linux_platform_layer/tests/CMakeLists.txt +++ b/src/platform_layers/linux_platform_layer/tests/CMakeLists.txt @@ -9,18 +9,18 @@ disablertti () set (sources main.cpp download_ut.cpp mock_do_download.cpp) +add_executable (${PROJECT_NAME} ${sources}) + find_package (Catch2 REQUIRED) find_package (IotHubClient REQUIRED) # NOTE: the call to find_package for azure_c_shared_utility # must come before umqtt since their config.cmake files expect # the aziotsharedutil target to already have been defined. -find_package (azure_c_shared_utility REQUIRED) +target_link_aziotsharedutil (${PROJECT_NAME} PRIVATE) find_package (umqtt REQUIRED) -add_executable (${PROJECT_NAME} ${sources}) - target_include_directories (${PROJECT_NAME} PRIVATE ${ADUC_EXPORT_INCLUDES}) target_link_libraries ( @@ -33,9 +33,8 @@ target_link_libraries ( aduc::exception_utils aduc::c_utils atomic - Catch2::Catch2) - -target_link_libraries (${PROJECT_NAME} PRIVATE libaducpal) + Catch2::Catch2 + libaducpal) include (CTest) include (Catch) diff --git a/src/rootkey_workflow/CMakeLists.txt b/src/rootkey_workflow/CMakeLists.txt new file mode 100644 index 000000000..28f6c8a7e --- /dev/null +++ b/src/rootkey_workflow/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required (VERSION 3.5) + +set (target_name rootkey_workflow) +include (agentRules) +compileasc99 () + +add_library (${target_name} STATIC src/rootkey_workflow.c) +add_library (aduc::${target_name} ALIAS ${target_name}) + +target_include_directories (${target_name} PUBLIC inc ${ADUC_EXPORT_INCLUDES}) + +target_link_aziotsharedutil (${target_name} PRIVATE) +find_package (Parson) + +# +# Turn -fPIC on, in order to use this library in another shared library. +# +set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_compile_definitions ( + ${target_name} + PRIVATE ADUC_ROOTKEY_STORE_PACKAGE_PATH="${ADUC_ROOTKEY_STORE_PACKAGE_PATH}" + ADUC_ROOTKEY_STORE_PATH="${ADUC_ROOTKEY_STORE_PATH}" + ADUC_ROOTKEY_PKG_URL_OVERRIDE="${ADUC_ROOTKEY_PKG_URL_OVERRIDE}") + +include (CMakePrintHelpers) +cmake_print_variables (ADUC_ENABLE_E2E_TESTING) +if (ADUC_ENABLE_E2E_TESTING) + cmake_print_variables (ADUC_ENABLE_E2E_TESTING) + target_compile_definitions (${target_name} PRIVATE ADUC_E2E_TESTING_ENABLED="true") +endif () + +if (ADUC_ENABLE_SRVC_E2E_TESTING) + cmake_print_variables (ADUC_ENABLE_SRVC_E2E_TESTING) + target_compile_definitions (${target_name} PRIVATE ADUC_ENABLE_SRVC_E2E_TESTING="true") +endif () + +target_link_libraries ( + ${target_name} + PUBLIC aduc::c_utils + PRIVATE aduc::rootkeypackage_utils aduc::root_key_utils aduc::logging aduc::system_utils) + +if (ADUC_BUILD_UNIT_TESTS) + add_subdirectory (tests) +endif () diff --git a/src/rootkey_workflow/inc/aduc/rootkey_workflow.h b/src/rootkey_workflow/inc/aduc/rootkey_workflow.h new file mode 100644 index 000000000..b7de10d73 --- /dev/null +++ b/src/rootkey_workflow/inc/aduc/rootkey_workflow.h @@ -0,0 +1,21 @@ +/** + * @file diagnostics_devicename.h + * @brief Header file describing the methods for setting the static global device name for use in the diagnostic component + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#ifndef ROOTKEY_WORKFLOW_H +#define ROOTKEY_WORKFLOW_H + +#include +#include +#include + +EXTERN_C_BEGIN + +ADUC_Result RootKeyWorkflow_UpdateRootKeys(const char* workflowId, const char* workFolder, const char* rootKeyPkgUrl); + +EXTERN_C_END + +#endif // ROOTKEY_WORKFLOW_H diff --git a/src/rootkey_workflow/src/rootkey_workflow.c b/src/rootkey_workflow/src/rootkey_workflow.c new file mode 100644 index 000000000..e710cb6f8 --- /dev/null +++ b/src/rootkey_workflow/src/rootkey_workflow.c @@ -0,0 +1,189 @@ +/** + * @file diagnostics_devicename.c + * @brief Implements function necessary for getting and setting the devicename for the diagnostics_component + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "aduc/rootkey_workflow.h" + +#include +#include +#include +#include +#include +#include +#include // ADUC_Result_RootKey_Continue +#include +#include +#include +#include + +#include + +/** + * @brief Downloads the root key package and updates local store with it if different from current. + * @param[in] workflowId The workflow Id for use in loca dir path of the rootkey package download. + * @param[in] workFolder The working dir for downloaded update payloads. + * @param[in] rootKeyPkgUrl The URL of the rootkey package from the deployment metadata. + * @returns ADUC_Result the result. + * @details If local storage is not being used then the contents of outLocalStoreChanged will always be true. + */ +ADUC_Result RootKeyWorkflow_UpdateRootKeys(const char* workflowId, const char* workFolder, const char* rootKeyPkgUrl) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + ADUC_Result tmpResult = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + STRING_HANDLE downloadedFilePath = NULL; + STRING_HANDLE fileDest = NULL; + JSON_Value* rootKeyPackageJsonValue = NULL; + char* rootKeyPackageJsonString = NULL; + ADUC_RootKeyPackage rootKeyPackage; + + memset(&rootKeyPackage, 0, sizeof(ADUC_RootKeyPackage)); + + ADUC_RootKeyPkgDownloaderInfo rootkey_downloader_info = { + .name = "DO", // DeliveryOptimization + .downloadFn = DownloadRootKeyPkg_DO, + .downloadBaseDir = workFolder, + }; + + if (workflowId == NULL) + { + result.ExtendedResultCode = ADUC_ERC_INVALIDARG; + goto done; + } + + RootKeyUtility_ClearReportingErc(); + + tmpResult = ADUC_RootKeyPackageUtils_DownloadPackage( + rootKeyPkgUrl, workflowId, &rootkey_downloader_info, &downloadedFilePath); + + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + result = tmpResult; + goto done; + } + + rootKeyPackageJsonValue = json_parse_file(STRING_c_str(downloadedFilePath)); + + if (rootKeyPackageJsonValue == NULL) + { + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_PARSE; + goto done; + } + + rootKeyPackageJsonString = json_serialize_to_string(rootKeyPackageJsonValue); + + if (rootKeyPackageJsonString == NULL) + { + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_PKG_FAIL_JSON_SERIALIZE; + goto done; + } + + tmpResult = ADUC_RootKeyPackageUtils_Parse(rootKeyPackageJsonString, &rootKeyPackage); + + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + result = tmpResult; + goto done; + } + + tmpResult = RootKeyUtility_ValidateRootKeyPackageWithHardcodedKeys(&rootKeyPackage); + + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + result = tmpResult; + goto done; + } + +#ifndef ADUC_ENABLE_SRVC_E2E_TESTING + +#ifdef ADUC_E2E_TESTING_ENABLED + if (!rootKeyPackage.protectedProperties.isTest) + { + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_PROD_PKG_ON_TEST_AGENT; + goto done; + } +#else + if (rootKeyPackage.protectedProperties.isTest) + { + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_TEST_PKG_ON_PROD_AGENT; + goto done; + } +#endif + +#endif + if (!ADUC_SystemUtils_Exists(ADUC_ROOTKEY_STORE_PATH)) + { + if (ADUC_SystemUtils_MkDirRecursiveDefault(ADUC_ROOTKEY_STORE_PATH) != 0) + { + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_STORE_PATH_CREATE; + goto done; + } + } + + fileDest = STRING_construct(ADUC_ROOTKEY_STORE_PACKAGE_PATH); + + if (fileDest == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + if (!ADUC_RootKeyUtility_IsUpdateStoreNeeded(fileDest, rootKeyPackageJsonString)) + { + // This is a success, but skips writing to local store and includes informational ERC. + result.ResultCode = ADUC_Result_RootKey_Continue; + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_PKG_UNCHANGED; + goto done; + } + + tmpResult = RootKeyUtility_WriteRootKeyPackageToFileAtomically(&rootKeyPackage, fileDest); + + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + result = tmpResult; + goto done; + } + + tmpResult = RootKeyUtility_ReloadPackageFromDisk(STRING_c_str(fileDest), true /* validateSignatures */); + + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + result = tmpResult; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_PACKAGE_CHANGED; + +done: + + if (IsAducResultCodeFailure(result.ResultCode) || result.ResultCode == ADUC_Result_RootKey_Continue) + { + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("Fail update root keys, ERC 0x%08x", result.ExtendedResultCode); + } + else + { + Log_Debug("No root key change."); + } + } + else + { + Log_Info("Update RootKey, ResultCode %d, ERC 0x%08x", result.ResultCode, result.ExtendedResultCode); + } + + RootKeyUtility_SetReportingErc(result.ExtendedResultCode); + + STRING_delete(downloadedFilePath); + STRING_delete(fileDest); + json_value_free(rootKeyPackageJsonValue); + free(rootKeyPackageJsonString); + + ADUC_RootKeyPackageUtils_Destroy(&rootKeyPackage); + return result; +} diff --git a/src/rootkey_workflow/tests/CMakeLists.txt b/src/rootkey_workflow/tests/CMakeLists.txt new file mode 100644 index 000000000..2870d51cd --- /dev/null +++ b/src/rootkey_workflow/tests/CMakeLists.txt @@ -0,0 +1,21 @@ +set (target_name rootkey_workflow_unit_test) + +include (agentRules) +compileasc99 () +disablertti () + +find_package (Catch2 REQUIRED) + +add_executable (${target_name}) +target_sources (${target_name} PRIVATE main.cpp rootkey_workflow_ut.cpp) + +target_link_libraries ( + ${target_name} + PRIVATE Catch2::Catch2 + aduc::c_utils + aduc::rootkey_workflow + aduc::root_key_utils) + +include (CTest) +include (Catch) +catch_discover_tests (${target_name}) diff --git a/src/rootkey_workflow/tests/main.cpp b/src/rootkey_workflow/tests/main.cpp new file mode 100644 index 000000000..78d9e3802 --- /dev/null +++ b/src/rootkey_workflow/tests/main.cpp @@ -0,0 +1,25 @@ +/** + * @file main.cpp + * @brief rootkey_workflow tests main entry point. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +// https://github.com/catchorg/Catch2/blob/master/docs/own-main.md +#define CATCH_CONFIG_RUNNER +#include + +#include + +int main(int argc, char* argv[]) +{ + int result; + + result = Catch::Session().run(argc, argv); + if (result != 0) + { + std::cout << "Catch session failed, err=" << result << std::endl; + } + + return result; +} diff --git a/src/rootkey_workflow/tests/rootkey_workflow_ut.cpp b/src/rootkey_workflow/tests/rootkey_workflow_ut.cpp new file mode 100644 index 000000000..ec3252777 --- /dev/null +++ b/src/rootkey_workflow/tests/rootkey_workflow_ut.cpp @@ -0,0 +1,28 @@ +/** + * @file rootkey_workflow_ut.cpp + * @brief Unit Tests for rootkey_workflow library + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "aduc/rootkey_workflow.h" // RootKeyWorkflow_UpdateRootKeys +#include +#include +#include +#include // RootKeyUtility_GetReportingErc + +using Catch::Matchers::Equals; + +TEST_CASE("RootKeyWorkflow_UpdateRootKeys") +{ + SECTION("rootkeyutil reporting erc set on failure") + { + ADUC_Result result = RootKeyWorkflow_UpdateRootKeys(nullptr /* workflowId */, nullptr /* workFolder */, nullptr /* rootKeyPkgUrl */); + REQUIRE(IsAducResultCodeFailure(result.ResultCode)); + CHECK(result.ExtendedResultCode == ADUC_ERC_INVALIDARG); + + ADUC_Result_t ercForReporting = RootKeyUtility_GetReportingErc(); + CHECK(ercForReporting == result.ExtendedResultCode); + } +} diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index e35c261fd..fcea2b016 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -11,7 +11,6 @@ add_subdirectory (exception_utils) add_subdirectory (extension_utils) add_subdirectory (file_utils) add_subdirectory (hash_utils) -add_subdirectory (https_proxy_utils) add_subdirectory (installed_criteria_utils) add_subdirectory (permission_utils) add_subdirectory (parson_json_utils) @@ -19,9 +18,13 @@ add_subdirectory (jws_utils) add_subdirectory (parser_utils) add_subdirectory (path_utils) add_subdirectory (process_utils) +add_subdirectory (reporting_utils) add_subdirectory (retry_utils) +add_subdirectory (rootkeypackage_utils) +add_subdirectory (root_key_utils) add_subdirectory (string_utils) add_subdirectory (system_utils) +add_subdirectory (url_utils) add_subdirectory (workflow_data_utils) add_subdirectory (workflow_utils) diff --git a/src/utils/c_utils/inc/aduc/string_c_utils.h b/src/utils/c_utils/inc/aduc/string_c_utils.h index 2251fd7df..f16f08f67 100644 --- a/src/utils/c_utils/inc/aduc/string_c_utils.h +++ b/src/utils/c_utils/inc/aduc/string_c_utils.h @@ -17,6 +17,7 @@ EXTERN_C_BEGIN char* ADUC_StringUtils_Trim(char* str); +char* ADUC_StringUtils_Map(const char* src, int (*mapFn)(int)); bool ADUC_ParseUpdateType(const char* updateType, char** updateTypeName, unsigned int* updateTypeVersion); diff --git a/src/utils/c_utils/src/string_c_utils.c b/src/utils/c_utils/src/string_c_utils.c index a9ea5d4b8..e688d9685 100644 --- a/src/utils/c_utils/src/string_c_utils.c +++ b/src/utils/c_utils/src/string_c_utils.c @@ -409,7 +409,45 @@ bool MallocAndSubstr(char** target, char* source, size_t len) } /** - * @brief Safely copies a source string to a destination buffer. + * @brief Produces a new string where each character is replaced with output of @p mapFn call. + * + * @param src The source string (will not be mutated). + * @param mapFn The mapping function. + * @return char* The new string with characters mapped. Caller owns and must call free(). NULL is returned on failures. + * @details returns NULL if string is null or empty. e.g. char* mapped = ADUC_StringUtils_Map(str, tolower); + */ +char* ADUC_StringUtils_Map(const char* src, int (*mapFn)(int)) +{ + char* tgt = NULL; + size_t len = strlen(src); + + if (src == NULL || len == 0) + { + return NULL; + } + + tgt = (char*)calloc(1, len + 1); + if (tgt == NULL) + { + return NULL; + } + + for (int i = 0; i <= len; ++i) + { + int ret = mapFn(src[i]); + + if (ret == EOF) + { + free(tgt); + return NULL; + } + tgt[i] = (char) ( ret & 0xFF); + } + + return tgt; +} + +/** @brief Safely copies a source string to a destination buffer. * * This function is a safer alternative to strncpy. It ensures that the * destination buffer is always null-terminated and won't cause buffer diff --git a/src/utils/crypto_utils/CMakeLists.txt b/src/utils/crypto_utils/CMakeLists.txt index 186cc2050..eef8fb8f3 100644 --- a/src/utils/crypto_utils/CMakeLists.txt +++ b/src/utils/crypto_utils/CMakeLists.txt @@ -2,32 +2,28 @@ cmake_minimum_required (VERSION 3.5) set (target_name crypto_utils) -add_library (${target_name} STATIC src/crypto_lib.c src/root_key_util.c src/base64_utils.c) +add_library (${target_name} STATIC src/crypto_lib.c src/base64_utils.c) add_library (aduc::${target_name} ALIAS ${target_name}) target_include_directories (${target_name} PUBLIC inc) find_package (OpenSSL REQUIRED) -message(OPENSSL_CRYPTO_LIBRARY="${OPENSSL_CRYPTO_LIBRARY}") -message(OPENSSL_VERSION="${OPENSSL_VERSION}") -message(OPENSSL_INCLUDE_DIR="${OPENSSL_INCLUDE_DIR}") -message(OPENSSL_SSL_LIBRARY="${OPENSSL_SSL_LIBRARY}") # # Turn -fPIC on, in order to use this library in another shared library. # set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_aziotsharedutil (${target_name} PRIVATE) +target_link_aziotsharedutil (${target_name} PUBLIC) target_link_libraries ( ${target_name} PUBLIC aduc::c_utils - PRIVATE OpenSSL::Crypto libaducpal) + PRIVATE aduc::root_key_utils OpenSSL::Crypto) +target_link_libraries (${target_name} PRIVATE libaducpal) -# Always support test root keys. -add_definitions (-DBUILD_WITH_TEST_KEYS=1) +target_compile_definitions (${target_name} PRIVATE EMBED_TEST_ROOT_KEYS=${EMBED_TEST_ROOT_KEYS}) if (ADUC_BUILD_UNIT_TESTS) add_subdirectory (tests) diff --git a/src/utils/crypto_utils/inc/crypto_lib.h b/src/utils/crypto_utils/inc/crypto_lib.h index 3ca9bfe13..7b690ca15 100644 --- a/src/utils/crypto_utils/inc/crypto_lib.h +++ b/src/utils/crypto_utils/inc/crypto_lib.h @@ -8,6 +8,7 @@ #include "crypto_key.h" #include +#include #include #include #include @@ -17,11 +18,16 @@ EXTERN_C_BEGIN +// +// Signature Algorithms +// + +# define CRYPTO_UTILS_SIGNATURE_VALIDATION_ALG_RS256 "rs256" // // Signature Verification // -bool IsValidSignature( +bool CryptoUtils_IsValidSignature( const char* alg, const uint8_t* expectedSignature, size_t sigLength, @@ -33,15 +39,21 @@ bool IsValidSignature( // Key Helper Functions // -CryptoKeyHandle RSAKey_ObjFromBytes(uint8_t* N, size_t N_len, uint8_t* e, size_t e_len); +CryptoKeyHandle RSAKey_ObjFromBytes(const uint8_t* N, size_t N_len, const uint8_t* e, size_t e_len); CryptoKeyHandle RSAKey_ObjFromB64Strings(const char* encodedN, const char* encodedE); +CryptoKeyHandle RSAKey_ObjFromModulusBytesExponentInt(const uint8_t* N, size_t N_len, const unsigned int e); + CryptoKeyHandle RSAKey_ObjFromStrings(const char* N, const char* e); CryptoKeyHandle GetRootKeyForKeyID(const char* kid); -void FreeCryptoKeyHandle(CryptoKeyHandle key); +void CryptoUtils_FreeCryptoKeyHandle(CryptoKeyHandle key); + +CONSTBUFFER_HANDLE CryptoUtils_CreateSha256Hash(const CONSTBUFFER_HANDLE buf); + +CONSTBUFFER_HANDLE CryptoUtils_GenerateRsaPublicKey(const char* modulus_b64url, const char* exponent_b64url); EXTERN_C_END diff --git a/src/utils/crypto_utils/src/crypto_lib.c b/src/utils/crypto_utils/src/crypto_lib.c index 682eabcb8..0b4b32ea6 100644 --- a/src/utils/crypto_utils/src/crypto_lib.c +++ b/src/utils/crypto_utils/src/crypto_lib.c @@ -13,8 +13,8 @@ #include #include #include - #if OPENSSL_VERSION_NUMBER >= 0x30000000L +# include # include #endif @@ -24,6 +24,7 @@ #include // strcasecmp +#define SHA256NUMBYTES 32 /** * @brief Algorithm_Id values and supported algorithms */ @@ -37,6 +38,23 @@ typedef enum tagAlgorithm_Id // Helper Functions // +/** + * @brief Get the Evp Md (message digest) from Sha Alg string. + * + * @param alg The sha alg str, e.g. "sha256" + * @return const EVP_MD* The corresponding sha alg EVP_MD, or NULL if not supported. + */ +static const EVP_MD* GetEvpMdFromShaAlg(const char* alg) +{ + if (strcmp(alg, "sha256") == 0) + { + return EVP_sha256(); + } + + // unsupported + return NULL; +} + /** * @brief Helper function that casts the CryptoKeyHandle to the EVP_PKEY struct * @details The CryptoKey pointed to by handle MUST have been created using one of the crypto_lib function @@ -169,7 +187,7 @@ bool VerifyRS256Signature( * @param keyToSign key that should be used for generating the computed signature. May be NULL depending on the algorithm * @returns true if the signature is valid, false if it is invalid */ -bool IsValidSignature( +bool CryptoUtils_IsValidSignature( const char* alg, const uint8_t* expectedSignature, size_t sigLength, @@ -199,6 +217,200 @@ bool IsValidSignature( return result; } +CryptoKeyHandle RSAKey_ObjFromModulusBytesExponentInt(const uint8_t* N, size_t N_len, const unsigned int e) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + int status = 0; + EVP_PKEY* result = NULL; + EVP_PKEY_CTX* ctx = NULL; + OSSL_PARAM_BLD* param_bld = NULL; + OSSL_PARAM* params = NULL; + BIGNUM* bn_N = NULL; + BIGNUM* bn_e = NULL; + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + + if (ctx == NULL) + { + goto done; + } + + bn_N = BN_new(); + + if (bn_N == NULL) + { + goto done; + } + + bn_e = BN_new(); + + if (bn_e == NULL) + { + goto done; + } + + if (BN_bin2bn(N, (int)N_len, bn_N) == 0) + { + goto done; + } + + if (BN_set_word(bn_e, e) == 0) + { + goto done; + } + + param_bld = OSSL_PARAM_BLD_new(); + + if (param_bld == NULL) + { + goto done; + } + + status = OSSL_PARAM_BLD_push_BN(param_bld, "n", bn_N); + if (status != 1) + { + goto done; + } + + status = OSSL_PARAM_BLD_push_BN(param_bld, "e", bn_e); + if (status != 1) + { + goto done; + } + + status = OSSL_PARAM_BLD_push_BN(param_bld, "d", NULL); + if (status != 1) + { + goto done; + } + + params = OSSL_PARAM_BLD_to_param(param_bld); + if (params == NULL) + { + goto done; + } + + status = EVP_PKEY_fromdata_init(ctx); + if (status != 1) + { + goto done; + } + + status = EVP_PKEY_fromdata(ctx, &result, EVP_PKEY_PUBLIC_KEY, params); + if (status != 1) + { + goto done; + } +done: + + if (ctx != NULL) + { + EVP_PKEY_CTX_free(ctx); + } + + if (param_bld != NULL) + { + OSSL_PARAM_BLD_free(param_bld); + } + + if (params != NULL) + { + OSSL_PARAM_free(params); + } + + if (bn_N != NULL) + { + BN_free(bn_N); + } + + if (bn_e != NULL) + { + BN_free(bn_e); + } + + if (status == 0 && result != NULL) + { + EVP_PKEY_free(result); + result = NULL; + } + + return CryptoKeyHandleToEVP_PKEY(result); + +#else + _Bool success = false; + EVP_PKEY* pkey = NULL; + + BIGNUM* rsa_N = NULL; + BIGNUM* rsa_e = NULL; + + RSA* rsa = RSA_new(); + + if (rsa == NULL) + { + goto done; + } + + rsa_N = BN_bin2bn(N, (int)N_len, NULL); + + if (rsa_N == NULL) + { + goto done; + } + + rsa_e = BN_new(); + + if (rsa_e == NULL) + { + goto done; + } + + if (BN_set_word(rsa_e, e) == 0) + { + goto done; + } + + if (RSA_set0_key(rsa, rsa_N, rsa_e, NULL) == 0) + { + goto done; + } + + pkey = EVP_PKEY_new(); + + if (pkey == NULL) + { + goto done; + } + + if (EVP_PKEY_assign_RSA(pkey, rsa) == 0) + { + goto done; + } + + success = true; + +done: + + if (!success) + { + if (pkey != NULL) + { + EVP_PKEY_free(pkey); + } + else if (rsa != NULL) + { + RSA_free(rsa); + } + else + { + BN_free(rsa_N); + BN_free(rsa_e); + } + } + + return CryptoKeyHandleToEVP_PKEY(pkey); +#endif +} + /** * @brief Makes an RSA Key from the modulus (N) and exponent (e) provided in their byte format * @param N a buffer containing the bytes for the modulus @@ -207,7 +419,7 @@ bool IsValidSignature( * @param e_len the length of the exponent buffer * @returns NULL on failure and a key on success */ -CryptoKeyHandle RSAKey_ObjFromBytes(uint8_t* N, size_t N_len, uint8_t* e, size_t e_len) +CryptoKeyHandle RSAKey_ObjFromBytes(const uint8_t* N, size_t N_len, const uint8_t* e, size_t e_len) { #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) int status = 0; @@ -327,7 +539,8 @@ CryptoKeyHandle RSAKey_ObjFromBytes(uint8_t* N, size_t N_len, uint8_t* e, size_t return CryptoKeyHandleToEVP_PKEY(result); #else - EVP_PKEY* result = NULL; + bool success = false; + EVP_PKEY* pkey = NULL; BIGNUM* rsa_N = NULL; BIGNUM* rsa_e = NULL; @@ -358,7 +571,7 @@ CryptoKeyHandle RSAKey_ObjFromBytes(uint8_t* N, size_t N_len, uint8_t* e, size_t goto done; } - EVP_PKEY* pkey = EVP_PKEY_new(); + pkey = EVP_PKEY_new(); if (pkey == NULL) { @@ -370,17 +583,30 @@ CryptoKeyHandle RSAKey_ObjFromBytes(uint8_t* N, size_t N_len, uint8_t* e, size_t goto done; } - result = pkey; + success = true; done: - if (result == NULL) + if (!success) { - BN_free(rsa_N); - BN_free(rsa_e); + if (pkey != NULL) + { + EVP_PKEY_free(pkey); + } + else if (rsa != NULL) + { + RSA_free(rsa); + } + else + { + BN_free(rsa_N); + BN_free(rsa_e); + } + + pkey = NULL; } - return CryptoKeyHandleToEVP_PKEY(result); -#endif + return CryptoKeyHandleToEVP_PKEY(pkey); +#endif // #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) } /** @@ -555,9 +781,19 @@ CryptoKeyHandle RSAKey_ObjFromStrings(const char* N, const char* e) done: if (result == NULL) { - BN_free(M); - BN_free(E); - EVP_PKEY_free(pkey); + if (pkey != NULL) + { + EVP_PKEY_free(pkey); + } + else if (rsa != NULL) + { + RSA_free(rsa); + } + else + { + BN_free(M); + BN_free(E); + } } return CryptoKeyHandleToEVP_PKEY(result); @@ -602,18 +838,270 @@ CryptoKeyHandle RSAKey_ObjFromB64Strings(const char* encodedN, const char* encod * @details Caller should assume the key is invalid after this call * @param key the key to free */ -void FreeCryptoKeyHandle(CryptoKeyHandle key) +void CryptoUtils_FreeCryptoKeyHandle(CryptoKeyHandle key) { EVP_PKEY_free(CryptoKeyHandleToEVP_PKEY(key)); } /** - * @brief Returns the master key for the provided kid - * @details this cals into the master_key_utility to get the key - * @param kid the key identifier - * @returns NULL on failure and a pointer to a key on success. + * @brief Computes a SHA256 hash from bytes. + * + * @param buf The handle to the input bytes to be hashed. + * @return CONSTBUFFER_HANDLE The digest buffer handle. Caller will own it and need to call CONSTBUFFER_DecRef() to free. */ -CryptoKeyHandle GetRootKeyForKeyID(const char* kid) +CONSTBUFFER_HANDLE CryptoUtils_CreateSha256Hash(const CONSTBUFFER_HANDLE buf) +{ + unsigned char hashBuf[SHA256NUMBYTES]; + memset(hashBuf, 0, sizeof(hashBuf)); + const CONSTBUFFER* constbuf = CONSTBUFFER_GetContent(buf); + + CONSTBUFFER_HANDLE out_handle = NULL; + + const EVP_MD* msg_digest = NULL; + EVP_MD_CTX* mdctx; + + if (buf == NULL) + { + return NULL; + } + + // Initialize OpenSSL digest context + if ((mdctx = EVP_MD_CTX_new()) == NULL) + { + goto done; + } + + msg_digest = GetEvpMdFromShaAlg("sha256"); + if (msg_digest == NULL) + { + goto done; + } + + // Initialize OpenSSL digest operation + if (1 != EVP_DigestInit_ex(mdctx, msg_digest, NULL)) + { + goto done; + } + + // Hash the input data + if (1 != EVP_DigestUpdate(mdctx, constbuf->buffer, constbuf->size)) + { + goto done; + } + + // Finalize the digest and get the output + if (1 != EVP_DigestFinal_ex(mdctx, &hashBuf[0], NULL)) + { + goto done; + } + + out_handle = CONSTBUFFER_Create(hashBuf, sizeof(hashBuf)); + +done: + EVP_MD_CTX_free(mdctx); + + return out_handle; +} + +CONSTBUFFER_HANDLE CryptoUtils_GenerateRsaPublicKey(const char* modulus_b64url, const char* exponent_b64url) { - return GetKeyForKid(kid); + CONSTBUFFER_HANDLE publicKeyData = NULL; + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + unsigned char *modulus_bytes, *exponent_bytes; + int modulus_length, exponent_length; + int status = 0; + EVP_PKEY* pkey = NULL; + EVP_PKEY_CTX* ctx = NULL; + OSSL_ENCODER_CTX* pkey_encoder_ctx = NULL; + OSSL_PARAM_BLD* param_bld = NULL; + OSSL_PARAM* params = NULL; + + BIGNUM* bn_modulus = NULL; + BIGNUM* bn_exponent = NULL; + unsigned char* der_encoded_bytes = NULL; + size_t der_length = 0; + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + + modulus_length = (int)Base64URLDecode(modulus_b64url, &modulus_bytes); + if (modulus_length == 0) + { + goto done; + } + + exponent_length = (int)Base64URLDecode(exponent_b64url, &exponent_bytes); + if (exponent_length == 0) + { + goto done; + } + + bn_modulus = BN_bin2bn(modulus_bytes, modulus_length, NULL); + if (bn_modulus == NULL) + { + goto done; + } + + bn_exponent = BN_bin2bn(exponent_bytes, exponent_length, NULL); + if (bn_exponent == NULL) + { + goto done; + } + + param_bld = OSSL_PARAM_BLD_new(); + + if (param_bld == NULL) + { + goto done; + } + + status = OSSL_PARAM_BLD_push_BN(param_bld, "n", bn_modulus); + if (status != 1) + { + goto done; + } + + status = OSSL_PARAM_BLD_push_BN(param_bld, "e", bn_exponent); + if (status != 1) + { + goto done; + } + + status = OSSL_PARAM_BLD_push_BN(param_bld, "d", NULL); + if (status != 1) + { + goto done; + } + + params = OSSL_PARAM_BLD_to_param(param_bld); + if (params == NULL) + { + goto done; + } + + status = EVP_PKEY_fromdata_init(ctx); + if (status != 1) + { + goto done; + } + + status = EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params); + if (status != 1) + { + goto done; + } + + pkey_encoder_ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, "DER", NULL, NULL); + + if (pkey_encoder_ctx == NULL) + { + goto done; + } + + if (OSSL_ENCODER_to_data(pkey_encoder_ctx, &der_encoded_bytes, &der_length) != 1) + { + goto done; + } + + // copies bytes into new buffer, so let it free after done: + publicKeyData = CONSTBUFFER_Create(der_encoded_bytes, der_length); + +done: + + if (ctx != NULL) + { + EVP_PKEY_CTX_free(ctx); + } + + if (param_bld != NULL) + { + OSSL_PARAM_BLD_free(param_bld); + } + + if (params != NULL) + { + OSSL_PARAM_free(params); + } + + if (pkey_encoder_ctx != NULL) + { + OSSL_ENCODER_CTX_free(pkey_encoder_ctx); + } + + free(der_encoded_bytes); + free(modulus_bytes); + free(exponent_bytes); + + BN_free(bn_modulus); + BN_free(bn_exponent); + + // OpenSSL 3.0 took the guess work out of ownership so we can free the pkey in addition to the bn_modulus and bn_exponent + EVP_PKEY_free(pkey); +#else + unsigned char* modulus_bytes = NULL; + unsigned char* exponent_bytes = NULL; + int modulus_length, exponent_length; + BIGNUM* bn_modulus = NULL; + BIGNUM* bn_exponent = NULL; + RSA* rsa = NULL; + unsigned char* der_encoded_bytes = NULL; + int der_length = 0; + + modulus_length = (int)Base64URLDecode(modulus_b64url, &modulus_bytes); + if (modulus_length == 0) + { + goto done; + } + + exponent_length = (int)Base64URLDecode(exponent_b64url, &exponent_bytes); + if (exponent_length == 0) + { + goto done; + } + + bn_modulus = BN_bin2bn(modulus_bytes, modulus_length, NULL); + if (bn_modulus == NULL) + { + goto done; + } + + bn_exponent = BN_bin2bn(exponent_bytes, exponent_length, NULL); + if (bn_exponent == NULL) + { + goto done; + } + + rsa = RSA_new(); + if (rsa == NULL) + { + goto done; + } + + if (RSA_set0_key(rsa, bn_modulus, bn_exponent, NULL) == 0) + { + goto done; + } + + der_encoded_bytes = NULL; + der_length = i2d_RSAPublicKey(rsa, &der_encoded_bytes); // DER PKCS#1 + if (der_length == 0) + { + goto done; + } + + // copies bytes into new buffer, so let it free after done: + publicKeyData = CONSTBUFFER_Create(der_encoded_bytes, (size_t)der_length); + +done: + + free(der_encoded_bytes); + free(modulus_bytes); + free(exponent_bytes); + + // Do not explicitly free bn_modulus and bn_exponent + RSA_free(rsa); + +#endif + + return publicKeyData; } diff --git a/src/utils/crypto_utils/src/root_key_util.c b/src/utils/crypto_utils/src/root_key_util.c deleted file mode 100644 index 2889bb80d..000000000 --- a/src/utils/crypto_utils/src/root_key_util.c +++ /dev/null @@ -1,199 +0,0 @@ -/** - * @file root_key_util.c - * @brief Implements a static list of root keys used to verify keys and messages within crypto_lib and it's callers. - * these have exponents and parameters that have been extracted from their certs - * to ease the computation process but remain the same as the ones issued by the Authority - * - * @copyright Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - */ - -#include -#include -#include -#include -#include -#include - -#include "crypto_lib.h" -#include "root_key_util.h" -// -// Root Key Type Definitions -// - -typedef struct tagRSARootKey -{ - const char* kid; - const char* N; - const char* e; -} RSARootKey; - -// -// Root Keychain Definitions -// - -// clang-format off -static const RSARootKey RSARootKeyList[] = -{ - { - // kid - "ADU.200702.R", - // N - "00d5422eaf1154a3506587a24d5bba" - "1afba932dfe9995f0545c8afbd351d" - "89e8272758a3a8eec5c51e4ff792a6" - "12067d3d7db007f62c7fde6d2af5bc" - "49bc15eff081cb3f884f271d887128" - "6008b619d2d239d0051f3c768671bb" - "5958bcb1887bab5628bf3173443210" - "fd3dd3965cff4e5cb36bff8b849b8b" - "80b849d07dfad64058764dc0722775" - "cb9a2f9bb49f0f25f11cc51b0b5a30" - "7d2fb8efa7265853afd51d5501510d" - "e91ba20f3fd7e91d2041a6e6140aae" - "fef21c2ad6e4047bf6147eec0f9783" - "fa58fa813621b9a32bfad9610b1a94" - "f7c1be7f40144ac9fa357fef667000" - "b1fddbd7610d3b5874679489757696" - "7c9187d28e1197ee7b876c9a2f45d8" - "653f5270982acbc80463f5c947cf70" - "f4ed64a774a5238fb6edf71cd3b01c" - "6457125aa981841fa0e7501996b482" - "b1ac48e3e13282cb401facc459bc10" - "345182f9288da81e9bf5794575b2dc" - "9a114308be61cc9ac4cb7736ff83dd" - "a8714f518e0e7b4dfa79988dbefc82" - "7e4048a91201a8d97ef3a51bf1fb90" - "773e408718c9abd9f779", - // E - "010001" - }, - - { - // kid - "ADU.200703.R", - // N - "00b2a3b27416fabb20f95276e6273e" - "8041c6fecf30f9c896f5590aaa81e7" - "51838ac4f5173a2f2ae657d471ce8a" - "3def9a55763e99e2c2ae4cee2db878" - "f5a24e28f29c4e3965bcece40de5e3" - "38a859ab08a41bb4f4a052a338b346" - "2113cc3c6806defe00a6926ede4c47" - "10d61c9c24f5cd70e1f56a7c68131d" - "e1c5f6a84f219f867c44c58a991cc5" - "d3069b5a719d091cc364316ac51795" - "1d5d2af155c766d4e8f5d9a95b8ca2" - "6c62600537d732b073cbf74b362724" - "218c380ab818fef51560358b35ef1e" - "0f88a6138d7b7defb3e7b0c9a61c70" - "7bccf2298b87f7bd9db6886fac73ff" - "72f2ef482796728606a25ce37dceb0" - "9ee5c2d94ec4f37f78074b6588450c" - "11e5965634882d160e5942d2f7d9ed" - "1dedc93777447ee384369f5813ef6f" - "e4c344d477068acf5bc8801ca29865" - "0b35dc73c869d05ee825439ef6d8ab" - "05af51292355405810eab8e2cd5d79" - "ccecdfb45b98c7fae3d26c26ce2e2c" - "56e0cf8deefd93122f00498d1c8238" - "56a65d79444a1af3dc1610b3c12d27" - "11fe1b9805e4a3603199", - // E - "010001" - }, - -#ifdef BUILD_WITH_TEST_KEYS - { - // kid - "ADU.200703.R.T", - // N - "00d968acb92a150f32accf4d8198fd" - "9bba5589cf0ac31f884122029acf82" - "2d86897f2d8392a64d249e89ef0a21" - "01e596fd90a31402539d2a5baf3b69" - "c62a9f7992a6739bbeed86a8d46dee" - "5b67214e0aa3e53c7fb49d41e183fa" - "075ef5ffe4ecf797eeca84c1b46d45" - "b343bda79265075627b100f06963eb" - "b8cd94d1afc30e35b1ad3089eb548e" - "d22536d3a19d73cccf9bd38a3cc319" - "4d7cd26ca636363fff369a625764a9" - "51946756b8b60ba1e5e12a8b1f4aef" - "4c3f568b8c2fa9b84998999f9db283" - "20dff0c7865b82fbb54ddabf1d026d" - "deddc4cab8bddb36f1a0b93c139dc7" - "0c130d55c4b314b27a6c0edc451e37" - "9bc29455becefa249b16ddf9656196" - "764f5979596c506d60c276e8bb743b" - "e701f130c3b26ec70e1d29d5e7952a" - "2b0466b9f90c59d0e9df2904d86d0c" - "1e03f19e86428f3ef92ef66ccafa7d" - "0fc5fb1a40c2d2d7e25f5e0895350e" - "1eae1bbfeb6e62285c162a57eea8eb" - "995a224c9054caf8d066a43280681b" - "71747ff95e0737640ed23329b255fc" - "3ef54996bfea282b517d", - // E - "010001" - }, - - { - // kid - "ADU.200702.R.T", - // N - "00b9c28024c92c91554a8ed54b15da" - "da3127747136b655c9dd9257b9e34b" - "268376b6bf88585e81d605a034b646" - "63e553357d647e5dc8c727d35187be" - "13cec1ea3c93835e7d3ce6d5863303" - "b35043e139203345a63e142af6dd22" - "2a33a0070983f1ce229bcfd904703e" - "9ed38dd4c8244cc8b7fc7d027748eb" - "c15c236855292243caf07037878c58" - "92ce4fc12f2d091918dfcc9645f25f" - "aad4df95aa9ab756d3a6409a616e54" - "8be9b0bd011d4636bbda25b1e249c8" - "9a16fba2b9c9de541bb707a6d8d301" - "229f6d31fc2ae34cd9a2584b6e63fc" - "e85312462c64151e4cc9451010c1e1" - "f1c3f14348c777521888351b8ded06" - "f7aff4bd1cfa0536466f68e5153957" - "bb5946348c0148cd550472ad824f1e" - "37a745ef68b798133f83b06f9194f9" - "244f68bed72904870b497ec2860d32" - "0fe663c3b256644d449c819151313a" - "097703ad18a900cc65d03e5bed7f72" - "0be3d7d44cce2bf1da4873b1353760" - "e3b7de3ffe471d6357bc2717e0447e" - "d1a224020131dea7afa6416e542aaf" - "e89c95b66cda3b8bd19b", - // E - "010001" - }, -#endif -}; -// clang-format on - -/** - * @brief Helper function that returns a CryptoKeyHandle associated with the kid - * @details The caller must free the returned Key with the FreeCryptoKeyHandle() function - * @param kid the key identifier associated with the key - * @returns the CryptoKeyHandle on success, null on failure - */ -CryptoKeyHandle GetKeyForKid(const char* kid) -{ - // - // Iterate through the RSA Root Keys - // - const unsigned numberKeys = (sizeof(RSARootKeyList) / sizeof(RSARootKey)); - for (unsigned i = 0; i < numberKeys; ++i) - { - if (strcmp(RSARootKeyList[i].kid, kid) == 0) - { - return RSAKey_ObjFromStrings(RSARootKeyList[i].N, RSARootKeyList[i].e); - } - } - - return NULL; -} diff --git a/src/utils/crypto_utils/src/root_key_util.h b/src/utils/crypto_utils/src/root_key_util.h deleted file mode 100644 index b158c5af3..000000000 --- a/src/utils/crypto_utils/src/root_key_util.h +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @file root_key_util.h - * @brief Contains a list of Root Keys for ADU and functions for retrieving them - * - * @copyright Copyright (c) Microsoft Corporation. - * Licensed under the MIT License. - */ -#include "crypto_key.h" - -#ifndef ROOT_KEY_UTIL_H -# define ROOT_KEY_UTIL_H - -CryptoKeyHandle GetKeyForKid(const char* kid); - -#endif // ROOT_KEY_UTIL_H diff --git a/src/utils/crypto_utils/tests/CMakeLists.txt b/src/utils/crypto_utils/tests/CMakeLists.txt index a4b48f074..1e93336e4 100644 --- a/src/utils/crypto_utils/tests/CMakeLists.txt +++ b/src/utils/crypto_utils/tests/CMakeLists.txt @@ -14,12 +14,8 @@ find_package (OpenSSL REQUIRED) add_executable (${PROJECT_NAME} ${sources}) -message(OPENSSL_CRYPTO_LIBRARY="${OPENSSL_CRYPTO_LIBRARY}") -message(OPENSSL_VERSION="${OPENSSL_VERSION}") -message(OPENSSL_INCLUDE_DIR="${OPENSSL_INCLUDE_DIR}") -message(OPENSSL_SSL_LIBRARY="${OPENSSL_SSL_LIBRARY}") - -target_link_libraries (${PROJECT_NAME} PRIVATE aduc::crypto_utils aduc::string_utils Catch2::Catch2 OpenSSL::Crypto) +target_link_libraries (${PROJECT_NAME} PRIVATE aduc::crypto_utils aduc::root_key_utils + aduc::string_utils Catch2::Catch2 OpenSSL::Crypto) include (CTest) include (Catch) diff --git a/src/utils/crypto_utils/tests/crypto_utils_ut.cpp b/src/utils/crypto_utils/tests/crypto_utils_ut.cpp index 4e443da61..2bbb4bbe9 100644 --- a/src/utils/crypto_utils/tests/crypto_utils_ut.cpp +++ b/src/utils/crypto_utils/tests/crypto_utils_ut.cpp @@ -5,8 +5,10 @@ * @copyright Copyright (c) Microsoft Corporation. * Licensed under the MIT License. */ +#include "aduc/result.h" #include "base64_utils.h" #include "crypto_lib.h" +#include "root_key_util.h" #include #include #include @@ -60,21 +62,15 @@ TEST_CASE("RSA Keys") CHECK(key != nullptr); - FreeCryptoKeyHandle(key); - } - - SECTION("Getting a Root Key ID") - { - CryptoKeyHandle key = GetRootKeyForKeyID("ADU.200702.R"); - - CHECK(key != nullptr); - - FreeCryptoKeyHandle(key); + CryptoUtils_FreeCryptoKeyHandle(key); } SECTION("Failing to get a Root Key") { - CryptoKeyHandle key = GetRootKeyForKeyID("foo"); + CryptoKeyHandle key = nullptr; + + ADUC_Result result = RootKeyUtility_GetKeyForKidFromHardcodedKeys(&key, "foo"); + CHECK(IsAducResultCodeFailure(result.ResultCode)); CHECK(key == nullptr); } } @@ -107,13 +103,17 @@ TEST_CASE("Signature Verification") "CV29BMDVyQ1oiLCJlIjoiQVFBQiIsImFsZyI6IlJTMjU2Iiwia2lkIjoiQURVL" "jIwMDcwMi5SLlMifQ" }; - CryptoKeyHandle key = GetRootKeyForKeyID("ADU.200702.R"); + CryptoKeyHandle key = nullptr; + + ADUC_Result result = RootKeyUtility_GetKeyForKidFromHardcodedKeys(&key, "ADU.200702.R"); + + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); uint8_t* d_sig_handle = nullptr; size_t sig_len = Base64URLDecode(signature.c_str(), &d_sig_handle); - CHECK(IsValidSignature( - "RS256", + CHECK(CryptoUtils_IsValidSignature( + CRYPTO_UTILS_SIGNATURE_VALIDATION_ALG_RS256, d_sig_handle, sig_len, reinterpret_cast(blob.c_str()), // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) @@ -149,13 +149,18 @@ TEST_CASE("Signature Verification") "CV29BMDVyQ1oiLCJlIjoiQVFBQiIsImFsZyI6IlJTMjU2Iiwia2lkIjoiQURVL" "jIwMDcwMi5SLlMifQ" }; - CryptoKeyHandle key = GetRootKeyForKeyID("ADU.200702.R"); + CryptoKeyHandle key = NULL; + + ADUC_Result result = RootKeyUtility_GetKeyForKidFromHardcodedKeys(&key, "ADU.200702.R"); + + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + REQUIRE(key != nullptr); uint8_t* d_sig_handle = nullptr; size_t sig_len = Base64URLDecode(signature.c_str(), &d_sig_handle); - CHECK(!IsValidSignature( - "RS256", + CHECK(!CryptoUtils_IsValidSignature( + CRYPTO_UTILS_SIGNATURE_VALIDATION_ALG_RS256, d_sig_handle, sig_len, reinterpret_cast(blob.c_str()), // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) diff --git a/src/utils/entity_utils/CMakeLists.txt b/src/utils/entity_utils/CMakeLists.txt index 81c53ae34..878ca0bc1 100644 --- a/src/utils/entity_utils/CMakeLists.txt +++ b/src/utils/entity_utils/CMakeLists.txt @@ -4,6 +4,4 @@ add_library (${target_name} INTERFACE) add_library (aduc::${target_name} ALIAS ${target_name}) target_include_directories (${target_name} INTERFACE inc) - -find_package (azure_c_shared_utility REQUIRED) -target_link_libraries (${target_name} INTERFACE aziotsharedutil) +target_link_aziotsharedutil (${target_name} INTERFACE) diff --git a/src/utils/hash_utils/CMakeLists.txt b/src/utils/hash_utils/CMakeLists.txt index 636bf785e..f5cfa840e 100644 --- a/src/utils/hash_utils/CMakeLists.txt +++ b/src/utils/hash_utils/CMakeLists.txt @@ -17,7 +17,7 @@ target_link_aziotsharedutil (${target_name} PUBLIC) target_link_libraries ( ${target_name} - PUBLIC aduc::c_utils Parson::parson + PUBLIC aduc::c_utils aduc::adu_types Parson::parson PRIVATE aduc::logging aduc::string_utils) target_link_libraries (${target_name} PRIVATE libaducpal) diff --git a/src/utils/hash_utils/inc/aduc/hash_utils.h b/src/utils/hash_utils/inc/aduc/hash_utils.h index 6dcc48143..293044fed 100644 --- a/src/utils/hash_utils/inc/aduc/hash_utils.h +++ b/src/utils/hash_utils/inc/aduc/hash_utils.h @@ -80,6 +80,14 @@ void ADUC_Hash_FreeArray(size_t hashCount, ADUC_Hash* hashArray); */ bool ADUC_HashUtils_VerifyWithStrongestHash(const char* filePath, const ADUC_Hash* hashes, size_t hashCount); +/** + * @brief Whether the hash algorithm is valid. + * + * @param sha The SHA version. + * @return _Bool true if valid. + */ +bool ADUC_HashUtils_IsValidHashAlgorithm(SHAversion sha); + EXTERN_C_END #endif // ADUC_HASH_UTILS_H diff --git a/src/utils/hash_utils/src/hash_utils.c b/src/utils/hash_utils/src/hash_utils.c index 983960d60..d5a39f23d 100644 --- a/src/utils/hash_utils/src/hash_utils.c +++ b/src/utils/hash_utils/src/hash_utils.c @@ -88,7 +88,7 @@ static bool GetResultAndCompareHashes( return success; } -static inline bool IsValidFileHashCheckAlgorithm(SHAversion sha) +bool ADUC_HashUtils_IsValidHashAlgorithm(SHAversion sha) { return sha >= SHA256; } @@ -116,7 +116,7 @@ static bool ADUC_HashUtils_GetIndexStrongestValidHash( // Just because it's supported by the underlying library does not mean // it's valid for file digests (e.g. SHA1 is not valid). - if (!IsValidFileHashCheckAlgorithm(algVersion)) + if (!ADUC_HashUtils_IsValidHashAlgorithm(algVersion)) { Log_Warn("Invalid hash alg: %s", hashType); continue; diff --git a/src/utils/https_proxy_utils/tests/CMakeLists.txt b/src/utils/https_proxy_utils/tests/CMakeLists.txt deleted file mode 100644 index 09e4c89b0..000000000 --- a/src/utils/https_proxy_utils/tests/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -cmake_minimum_required (VERSION 3.5) - -project (https_proxy_utils_unit_tests) - -include (agentRules) - -compileasc99 () -disablertti () - -set (sources main.cpp https_proxy_utils_ut.cpp) - -find_package (Catch2 REQUIRED) - -add_executable (${PROJECT_NAME} ${sources}) - -target_link_libraries (${PROJECT_NAME} PRIVATE aduc::https_proxy_utils Catch2::Catch2) - -target_link_libraries (${PROJECT_NAME} PRIVATE libaducpal) - -include (CTest) -include (Catch) -catch_discover_tests (${PROJECT_NAME}) diff --git a/src/utils/installed_criteria_utils/tests/CMakeLists.txt b/src/utils/installed_criteria_utils/tests/CMakeLists.txt index 9d50ee066..a25aeec31 100644 --- a/src/utils/installed_criteria_utils/tests/CMakeLists.txt +++ b/src/utils/installed_criteria_utils/tests/CMakeLists.txt @@ -15,6 +15,11 @@ target_include_directories (${PROJECT_NAME} PRIVATE ${ADUC_EXPORT_INCLUDES}) target_sources (${PROJECT_NAME} PRIVATE main.cpp installed_criteria_utils_ut.cpp) +# Windows needs all EXEs to have links to all potential libraries so this is included here +if (WIN32) + target_link_dosdk (${PROJECT_NAME} PRIVATE) +endif () + target_compile_definitions ( ${PROJECT_NAME} PRIVATE ADUC_INSTALLEDCRITERIA_FILE_PATH="${ADUC_TMP_DIR_PATH}/adu-test-installedcriteria") diff --git a/src/utils/jws_utils/CMakeLists.txt b/src/utils/jws_utils/CMakeLists.txt index 0e5503512..92b377acc 100644 --- a/src/utils/jws_utils/CMakeLists.txt +++ b/src/utils/jws_utils/CMakeLists.txt @@ -22,7 +22,7 @@ target_link_aziotsharedutil (${target_name} PRIVATE) target_link_libraries ( ${target_name} PUBLIC aduc::crypto_utils aduc::c_utils - PRIVATE Parson::parson) + PRIVATE Parson::parson aduc::root_key_utils) if (ADUC_BUILD_UNIT_TESTS) add_subdirectory (tests) diff --git a/src/utils/jws_utils/inc/jws_utils.h b/src/utils/jws_utils/inc/jws_utils.h index 8f1507c99..0be63764e 100644 --- a/src/utils/jws_utils/inc/jws_utils.h +++ b/src/utils/jws_utils/inc/jws_utils.h @@ -33,6 +33,7 @@ #include "crypto_key.h" #include +#include #include #ifndef JWS_UTILS_H @@ -42,19 +43,31 @@ EXTERN_C_BEGIN /** * @brief Return Value for JWS Verification Calls + * @details NOTE: Needs to be kept in sync with jws_result_to_str() function. */ typedef enum tagJWSResult { - JWSResult_Failed = 0, /**< Failed*/ - JWSResult_Success, /**< Succeeded */ - JWSResult_BadStructure, /**< JWS structure is not correct*/ - JWSResult_UnsupportedAlg, /**< Algorithm used to sign the JWS is not supported */ - JWSResult_InvalidSignature, /** +#include #include +#include #include #include #include @@ -237,6 +242,61 @@ static bool ExtractJWSHeader(const char* jws, char** header) // Public Functions // +/** + * @brief converts JWSResult to const C string. + * + * @param r The jws result to convert. + * @return const char* The mapped-to string. + * @details NOTE: Needs to be kept in sync with JWSResult enum in jws_utils.h + */ +const char* jws_result_to_str(JWSResult r) +{ + switch (r) + { + case JWSResult_Failed: + return "Failed"; + + case JWSResult_Success: + return "Success"; + + case JWSResult_BadStructure: + return "BadStructure"; + + case JWSResult_InvalidSignature: + return "InvalidSignature"; + + case JWSResult_DisallowedRootKid: + return "DisallowedRootKid"; + + case JWSResult_MissingRootKid: + return "MissingRootKid"; + + case JWSResult_InvalidRootKid: + return "InvalidRootKid"; + + case JWSResult_InvalidEncodingJWSHeader: + return "JWSResult_InvalidEncodingJWSHeader"; + + case JWSResult_InvalidSJWKPayload: + return "JWSResult_InvalidSJWKPayload"; + + case JWSResult_DisallowedSigningKey: + return "DisallowedSigningKey"; + + case JWSResult_FailedGetDisabledSigningKeys: + return "JWSResult_FailedGetDisabledSigningKeys"; + + case JWSResult_FailGenPubKey: + return "JWSResult_FailGenPubKey"; + + case JWSResult_HashPubKeyFailed: + return "JWSResult_HashPubKeyFailed"; + + default: + return "???"; + } +} + /** * @brief Verifies the Base64URL encoded @p sjwk in Signed JSON Web Key (SJWK) format using the KiD found within the encoded JWKs Header * @details A Signed JSON Web Key (SJWK) is JWK in JSON Web Signature (JWS) format. The function parses the header for the kid, builds the associated key, and then verifies the signature of the JWK @@ -246,14 +306,22 @@ static bool ExtractJWSHeader(const char* jws, char** header) JWSResult VerifySJWK(const char* sjwk) { JWSResult retval = JWSResult_Failed; + JWSResult jwsResultIsSigningKeyDisallowed = JWSResult_Failed; + JWSResult jwsResultVerifyJwtSignature = JWSResult_Failed; + ADUC_Result result = { ADUC_GeneralResult_Failure, 0 }; + ADUC_Result resultGetDisabledSigningKeys = { ADUC_GeneralResult_Failure, 0 }; + VECTOR_HANDLE signingKeyDisallowed = NULL; char* header = NULL; + char* payload = NULL; + char* signature = NULL; char* jsonHeader = NULL; + char* jsonPayload = NULL; char* kid = NULL; void* rootKey = NULL; - if (!ExtractJWSHeader(sjwk, &header)) + if (!ExtractJWSSections(sjwk, &header, &payload, &signature)) { retval = JWSResult_BadStructure; goto done; @@ -275,28 +343,79 @@ JWSResult VerifySJWK(const char* sjwk) goto done; } - rootKey = GetRootKeyForKeyID(kid); + result = RootKeyUtility_GetKeyForKid(&rootKey, kid); - if (rootKey == NULL) + if (IsAducResultCodeFailure(result.ResultCode)) { - retval = JWSResult_InvalidKid; + if (result.ExtendedResultCode == ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_ROOTKEY_IS_DISABLED) + { + retval = JWSResult_DisallowedRootKid; + } + else if (result.ExtendedResultCode == ADUC_ERC_UTILITIES_ROOTKEYUTIL_NO_ROOTKEY_FOUND_FOR_KEYID) + { + retval = JWSResult_MissingRootKid; + } + else + { + retval = JWSResult_InvalidRootKid; + } + goto done; + } + + // First verify JWT structure and signature + jwsResultVerifyJwtSignature = VerifyJWSWithKey(sjwk, rootKey); + if (jwsResultVerifyJwtSignature != JWSResult_Success) + { + retval = jwsResultVerifyJwtSignature; + goto done; + } + + // Now, verify that signing key is not on the rootkey packages's Disallowed + resultGetDisabledSigningKeys = RootKeyUtility_GetDisabledSigningKeys(&signingKeyDisallowed); + if (IsAducResultCodeFailure(resultGetDisabledSigningKeys.ResultCode)) + { + retval = JWSResult_FailedGetDisabledSigningKeys; goto done; } - retval = VerifyJWSWithKey(sjwk, rootKey); + jsonPayload = Base64URLDecodeToString(payload); + + if (jsonPayload == NULL) + { + retval = JWSResult_Failed; + goto done; + } - if (retval != JWSResult_Success) + jwsResultIsSigningKeyDisallowed = IsSigningKeyDisallowed(jsonPayload, signingKeyDisallowed); + if (jwsResultIsSigningKeyDisallowed != JWSResult_Success) { + retval = jwsResultIsSigningKeyDisallowed; goto done; } + retval = JWSResult_Success; + done: + if (signingKeyDisallowed != NULL) + { + VECTOR_destroy(signingKeyDisallowed); + } if (header != NULL) { free(header); } + if (payload != NULL) + { + free(payload); + } + + if (signature != NULL) + { + free(signature); + } + if (kid != NULL) { free(kid); @@ -307,9 +426,14 @@ JWSResult VerifySJWK(const char* sjwk) free(jsonHeader); } + if (jsonPayload != NULL) + { + free(jsonPayload); + } + if (rootKey != NULL) { - FreeCryptoKeyHandle(rootKey); + CryptoUtils_FreeCryptoKeyHandle(rootKey); } return retval; @@ -340,7 +464,7 @@ JWSResult VerifyJWSWithSJWK(const char* jws) if (jsonHeader == NULL) { - result = JWSResult_Failed; + result = JWSResult_InvalidEncodingJWSHeader; goto done; } @@ -390,8 +514,81 @@ JWSResult VerifyJWSWithSJWK(const char* jws) if (key != NULL) { - FreeCryptoKeyHandle(key); + CryptoUtils_FreeCryptoKeyHandle(key); + } + return result; +} + +/** + * @brief Whether signing key in SJWK (header of JWS) is no longer trusted as per latest root key package on file. + * + * @param sjwkJsonStr The SJWK json string that is base64 URL decoded header section of the JWS. + * @param disabledHashOfPubKeysList The list of sha256 hashes of public keys of signing keys that are disabled. + * @return JWSResult Returns JWSResult_Success if not on Disallowed; JWSResult_DisallowedSigningKey if signing key was on Disallowed, or other failure JWSResult if failed whilst determining. + */ +JWSResult IsSigningKeyDisallowed(const char* sjwkJsonStr, VECTOR_HANDLE disabledHashOfPubKeysList) +{ + JWSResult result = JWSResult_Failed; + CONSTBUFFER_HANDLE pubkey = NULL; + CONSTBUFFER_HANDLE sha256HashPubKey = NULL; + + char* N = GetStringValueFromJSON(sjwkJsonStr, "n"); + char* e = GetStringValueFromJSON(sjwkJsonStr, "e"); + if (IsNullOrEmpty(N) || IsNullOrEmpty(e) + || strcmp(e, "AQAB") != 0) // AQAB is 65337 or 0x010001, the ubiquitous RSA exponent. + { + result = JWSResult_InvalidSJWKPayload; + goto done; + } + + pubkey = CryptoUtils_GenerateRsaPublicKey(N, e); + if (pubkey == NULL) + { + result = JWSResult_FailGenPubKey; + goto done; + } + + sha256HashPubKey = CryptoUtils_CreateSha256Hash(pubkey); + if (pubkey == NULL) + { + result = JWSResult_HashPubKeyFailed; + goto done; + } + +#ifdef TRACE_DISABLED_SIGNING_KEY + char* base64urlSha256HashPubKey = Base64URLEncode( + CONSTBUFFER_GetContent(sha256HashPubKey)->buffer, CONSTBUFFER_GetContent(sha256HashPubKey)->size); + printf("base64url encoding of sha256 hash of public key: %s\n", base64urlSha256HashPubKey); +#endif + + // See if the hash of public key is on the Disallowed List. + for (size_t i = 0; i < VECTOR_size(disabledHashOfPubKeysList); ++i) + { + const ADUC_RootKeyPackage_Hash* DisallowedEntry = + (ADUC_RootKeyPackage_Hash*)VECTOR_element(disabledHashOfPubKeysList, i); + + if ((DisallowedEntry->alg == SHA256) + && CONSTBUFFER_HANDLE_contain_same(sha256HashPubKey, DisallowedEntry->hash)) + { + result = JWSResult_DisallowedSigningKey; + goto done; + } + } + + result = JWSResult_Success; + +done: + + if (pubkey != NULL) + { + CONSTBUFFER_DecRef(pubkey); + } + + if (sha256HashPubKey != NULL) + { + CONSTBUFFER_DecRef(sha256HashPubKey); } + return result; } @@ -458,7 +655,7 @@ JWSResult VerifyJWSWithKey(const char* blob, CryptoKeyHandle key) size_t decodedSignatureLen = Base64URLDecode(signature, &decodedSignature); - if (!IsValidSignature( + if (!CryptoUtils_IsValidSignature( alg, decodedSignature, decodedSignatureLen, (uint8_t*)headerPlusPayload, strlen(headerPlusPayload), key)) { result = JWSResult_InvalidSignature; diff --git a/src/utils/jws_utils/tests/CMakeLists.txt b/src/utils/jws_utils/tests/CMakeLists.txt index c22e45515..7c2e2ed53 100644 --- a/src/utils/jws_utils/tests/CMakeLists.txt +++ b/src/utils/jws_utils/tests/CMakeLists.txt @@ -12,19 +12,21 @@ set (sources main.cpp jws_utils_ut.cpp) find_package (Catch2 REQUIRED) find_package (OpenSSL REQUIRED) -message(OPENSSL_CRYPTO_LIBRARY="${OPENSSL_CRYPTO_LIBRARY}") -message(OPENSSL_VERSION="${OPENSSL_VERSION}") -message(OPENSSL_INCLUDE_DIR="${OPENSSL_INCLUDE_DIR}") -message(OPENSSL_SSL_LIBRARY="${OPENSSL_SSL_LIBRARY}") add_executable (${PROJECT_NAME} ${sources}) target_link_aziotsharedutil (${PROJECT_NAME} PRIVATE) +target_compile_definitions (${PROJECT_NAME} + PRIVATE ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}") + target_link_libraries ( ${PROJECT_NAME} PRIVATE aduc::jws_utils aduc::crypto_utils + aduc::root_key_utils + aduc::rootkeypackage_utils aduc::string_utils + aduc::system_utils Catch2::Catch2 OpenSSL::Crypto) diff --git a/src/utils/jws_utils/tests/jws_utils_ut.cpp b/src/utils/jws_utils/tests/jws_utils_ut.cpp index 7369dc105..8ee7b4a9a 100644 --- a/src/utils/jws_utils/tests/jws_utils_ut.cpp +++ b/src/utils/jws_utils/tests/jws_utils_ut.cpp @@ -9,11 +9,37 @@ #include "crypto_lib.h" #include "jws_utils.h" #include +#include +#include +#include #include #include #include +#include +#include #include #include +#include +#include +#include + +#define ENABLE_MOCKS +#include "root_key_store.h" +#undef ENABLE_MOCKS + +static std::string get_valid_example_rootkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/jws_utils/testrootkeypkg.json"; + return path; +}; + +std::string g_mockedRootKeyStorePath = ""; + +const char* MockRootKeyStore_GetRootKeyStorePath() +{ + return g_mockedRootKeyStorePath.c_str(); +} #if OPENSSL_VERSION_NUMBER < 0x1010000fL # define RSA_get0_n(x) ((x)->n) @@ -106,7 +132,59 @@ bool CheckRSA_Key( return success; } -TEST_CASE("VerifySJWK") +class TestCaseFixture +{ +public: + TestCaseFixture() : m_testPath{ ADUC_SystemUtils_GetTemporaryPathName() } + { + g_mockedRootKeyStorePath = get_valid_example_rootkey_package_json_path(); + + ADUC_Result result = RootKeyUtility_ReloadPackageFromDisk(g_mockedRootKeyStorePath.c_str(), true); + std::cout << g_mockedRootKeyStorePath << std::endl; + CHECK(IsAducResultCodeSuccess(result.ResultCode)); + } + + ~TestCaseFixture() + { + } + + /** + * @brief Gets the base test temp path as a c_str. + * + * @return const char* The test path. + */ + const char* TestPath() const + { + return m_testPath.c_str(); + } + + /** + * @brief provides the instance to this text fixture object for asserting + * that the Context passed to the for-each callback matches the current + * TestCaseFixture instance. + * + * @return TestCaseFixture* The pointer to this instance. + */ + TestCaseFixture* Instance() + { + return this; + } + +private: + TestCaseFixture(const TestCaseFixture&) = delete; + TestCaseFixture& operator=(const TestCaseFixture&) = delete; + TestCaseFixture(TestCaseFixture&&) = delete; + TestCaseFixture& operator=(TestCaseFixture&&) = delete; + + std::string m_pkg{ + R"( {"protected":{"version":1,"published":1675972876,"disabledRootKeys":[],"disabledSigningKeys":[],"rootKeys":{"ADU.200702.R":{"keyType":"RSA","n":"1UIurxFUo1Blh6JNW7oa-6ky3-mZXwVFyK-9NR2J6CcnWKOo7sXFHk_3kqYSBn09fbAH9ix_3m0q9bxJvBXv8IHLP4hPJx2IcShgCLYZ0tI50AUfPHaGcbtZWLyxiHurVii_MXNEMhD9PdOWXP9OXLNr_4uEm4uAuEnQffrWQFh2TcByJ3XLmi-btJ8PJfEcxRsLWjB9L7jvpyZYU6_VHVUBUQ3pG6IPP9fpHSBBpuYUCq7-8hwq1uQEe_YUfuwPl4P6WPqBNiG5oyv62WELGpT3wb5_QBRKyfo1f-9mcACx_dvXYQ07WHRnlIl1dpZ8kYfSjhGX7nuHbJovRdhlP1JwmCrLyARj9clHz3D07WSndKUjj7bt9xzTsBxkVxJaqYGEH6DnUBmWtIKxrEjj4TKCy0AfrMRZvBA0UYL5KI2oHpv1eUV1styaEUMIvmHMmsTLdzb_g92ocU9Rjg57Tfp5mI2-_IJ-QEipEgGo2X7zpRvx-5B3PkCHGMmr2fd5","e":65537},"ADU.200703.R":{"keyType":"RSA","n":"sqOydBb6uyD5UnbmJz6AQcb-zzD5yJb1WQqqgedRg4rE9Rc6LyrmV9Rxzoo975pVdj6Z4sKuTO4tuHj1ok4o8pxOOWW87OQN5eM4qFmrCKQbtPSgUqM4s0YhE8w8aAbe_gCmkm7eTEcQ1hycJPXNcOH1anxoEx3hxfaoTyGfhnxExYqZHMXTBptacZ0JHMNkMWrFF5UdXSrxVcdm1Oj12albjKJsYmAFN9cysHPL90s2JyQhjDgKuBj-9RVgNYs17x4PiKYTjXt977PnsMmmHHB7zPIpi4f3vZ22iG-sc_9y8u9IJ5ZyhgaiXON9zrCe5cLZTsTzf3gHS2WIRQwR5ZZWNIgtFg5ZQtL32e0d7ck3d0R-44Q2n1gT72_kw0TUdwaKz1vIgByimGULNdxzyGnQXuglQ5722KsFr1EpI1VAWBDquOLNXXnM7N-0W5jH-uPSbCbOLixW4M-N7v2TEi8ASY0cgjhWpl15REoa89wWELPBLScR_huYBeSjYDGZ","e":65537}}},"signatures":[{"alg":"RS256","sig":"eW8Cn256fBmV0DfintpvKLKBJJ2estNVeBvriVcazxE0-R_eFfpA1lYFpaOTmVx1g8dcRFYCmCXnmqLcrEZFLRJ26GezCQxkMtgo5NhlzLAc5BhaWn4_HDx1Y1yObWvQf1ZYfMFIntEtCDYLK1DxmmtqFy-0uLBIC4vPXLCdW0g4sGlXskMt0caszgYSduHgAI6AicQqSGjAy6Sms3gWELR4xbSK765IDp4rWqXns_aLy8pbOgar4Uxusmz5ydmJ9p3epMIhthe1D_kNwhzg5egi5B_S3LgEbm5DiJwyewwNPdZH-xNzP4KhLUK0sZjXk21OE3pj5Ia-Eydkrm4K6puf_ZR1G_XwhLO8s0QKZnjYqIL_EldJdwcKnW6lZDOnkYYGb7NYYS8FxIP4AG8FannN0xD503fhd7bsyIQGaXEQwRZgV88oKQy_-EQFUZ2MvzAKq2Cg7_KoBFEfSmU5MZgPD-4OycU98bAtBVcK-3phFQPdtKPkqjaDqBF3pTK3"},{"alg":"RS256","sig":"Mj9AZXSqwu6NUWUvdLIbSMy--Yp68wWPOcsKSZ-9qToD0RIF7Q3rbgKCYC9FFzHzwBolBwsqZogHeEv0wGbj4EuCKRHrD1onc8AiBpUWD9QrySP8Ca3QzBeE1jDkGVJvmuYsviLzletYT-6GCEBBWuQyUSmbA0Az9x4sUg9BNF7M2_zyd4GGyHDSt9YVYJekv9IQwEinEUGW6wB8St_V3x4w1Pujl69azOI0VpTtXXTlw7xwyhq_gO4mCO40b8KBGdTdD1pHz_4UT4hHvoRl9nVRi4lKBCSEzpLr_Oqs2s7TwS13GEg-XMMkzd3jGVkFS9C9ezcJC8osaxg0i5z0g_lc785Rg1yXM-gytOYFn2xyWIzqvJ5CQn3XgkCO9lduYkEF78xHFNbsorup2c2GRZTdWpTwLEi0v6bv303CxhNMGJYiZull-lRVLANFVO_pewduE3DqDTs3PF2InX0m9_ve9XouDvooaw1q3Zk_BgNgcxQxSQv2ifP4EFrNvPg2"}]} )" + }; + + std::string m_testPath; + ADUC_RootKeyPackage* m_rootKeyPackage; +}; + +TEST_CASE_METHOD(TestCaseFixture, "VerifySJWK") { SECTION("Validate a Valid Signed JSON Web Key") { @@ -249,11 +327,11 @@ TEST_CASE("VerifySJWK") BUFFER_delete(byteNBuff); BUFFER_delete(byteEBuff); - FreeCryptoKeyHandle(key); + CryptoUtils_FreeCryptoKeyHandle(key); } } -TEST_CASE("VerifyJWSWithKey") +TEST_CASE_METHOD(TestCaseFixture, "VerifyJWSWithKey") { SECTION("Validate a Valid JWS with a key") { @@ -331,10 +409,10 @@ TEST_CASE("VerifyJWSWithKey") CryptoKeyHandle key = RSAKey_ObjFromB64Strings(N.c_str(), e.c_str()); CHECK(VerifyJWSWithKey(signedJWT.c_str(), key) == JWSResult_Success); - FreeCryptoKeyHandle(key); + CryptoUtils_FreeCryptoKeyHandle(key); } - SECTION("Validating an InValid JWS") + SECTION("Validating an Invalid JWS") { // Note: Key parameters used to sign the JWT std::string N{ "rHVBEFKR1vshg+AhIg/SDQO3x4kj3CUT7fGnJhAmuDhvHfj3gHzi0T2IAqC" @@ -411,7 +489,7 @@ TEST_CASE("VerifyJWSWithKey") CHECK(VerifyJWSWithKey(signedJWT.c_str(), key) == JWSResult_InvalidSignature); - FreeCryptoKeyHandle(key); + CryptoUtils_FreeCryptoKeyHandle(key); } SECTION("Getting the Payload from a JWT") @@ -429,7 +507,6 @@ TEST_CASE("VerifyJWSWithKey") std::string e{ "AQAB" }; - // JWT signed by the key above // JWT signed by the key above std::string signedJWT{ "eyJhbGciOiJSUzI1NiIsInNqd2siOiJleUpoYkdjaU9" "pSlNVekkxTmlJc0ltdHBaQ0k2SWtGRVZTNHlNREEzTU" @@ -507,6 +584,95 @@ TEST_CASE("VerifyJWSWithKey") CHECK(payload_len == expected_payload_len); CHECK(strcmp(payload.get(), expectedDecodedPayloadString) == 0); - FreeCryptoKeyHandle(key); + CryptoUtils_FreeCryptoKeyHandle(key); + } +} + +const char* AllowedSigningKey = + "ucKAJMkskVVKjtVLFdraMSd0cTa2Vcndkle540smg3a2v4hYXoHWBaA0tkZj5VM1fWR-XcjHJ9NRh74TzsHqPJODXn085tWGMwOzUEPhOSAzRaY-FCr23SIqM6AHCYPxziKbz9kEcD6e043UyCRMyLf8fQJ3SOvBXCNoVSkiQ8rwcDeHjFiSzk_BLy0JGRjfzJZF8l-q1N-Vqpq3VtOmQJphblSL6bC9AR1GNrvaJbHiSciaFvuiucneVBu3B6bY0wEin20x_CrjTNmiWEtuY_zoUxJGLGQVHkzJRRAQweHxw_FDSMd3UhiINRuN7Qb3r_S9HPoFNkZvaOUVOVe7WUY0jAFIzVUEcq2CTx43p0XvaLeYEz-DsG-RlPkkT2i-1ykEhwtJfsKGDTIP5mPDslZkTUScgZFRMToJdwOtGKkAzGXQPlvtf3IL49fUTM4r8dpIc7E1N2Djt94__kcdY1e8JxfgRH7RoiQCATHep6-mQW5UKq_onJW2bNo7i9Gb"; +const char* DisallowedSigningKey = + "2WisuSoVDzKsz02BmP2bulWJzwrDH4hBIgKaz4Ithol_LYOSpk0knonvCiEB5Zb9kKMUAlOdKluvO2nGKp95kqZzm77thqjUbe5bZyFOCqPlPH-0nUHhg_oHXvX_5Oz3l-7KhMG0bUWzQ72nkmUHViexAPBpY-u4zZTRr8MONbGtMInrVI7SJTbToZ1zzM-b04o8wxlNfNJspjY2P_82mmJXZKlRlGdWuLYLoeXhKosfSu9MP1aLjC-puEmYmZ-dsoMg3_DHhluC-7VN2r8dAm3e3cTKuL3bNvGguTwTnccMEw1VxLMUsnpsDtxFHjebwpRVvs76JJsW3fllYZZ2T1l5WWxQbWDCdui7dDvnAfEww7Juxw4dKdXnlSorBGa5-QxZ0OnfKQTYbQweA_GehkKPPvku9mzK-n0PxfsaQMLS1-JfXgiVNQ4erhu_625iKFwWKlfuqOuZWiJMkFTK-NBmpDKAaBtxdH_5Xgc3ZA7SMymyVfw-9UmWv-ooK1F9"; + +static CONSTBUFFER_HANDLE GetHashPubKey(const char* n) +{ + CONSTBUFFER_HANDLE pubkey = CryptoUtils_GenerateRsaPublicKey(n, "AQAB"); + REQUIRE(pubkey != nullptr); + + CONSTBUFFER_HANDLE hashed = CryptoUtils_CreateSha256Hash(pubkey); + CONSTBUFFER_DecRef(pubkey); + REQUIRE(hashed != nullptr); + + return hashed; +} + +static VECTOR_HANDLE GetSigningKeyDisallowedList(const char* signing_key_N) +{ + VECTOR_HANDLE disallowedSigningPubKeyHashes = VECTOR_create(sizeof(ADUC_RootKeyPackage_Hash)); + REQUIRE(disallowedSigningPubKeyHashes != nullptr); + + if (signing_key_N != nullptr) + { + CONSTBUFFER_HANDLE hashPubKeyHandle = GetHashPubKey(signing_key_N); + REQUIRE(hashPubKeyHandle != nullptr); + + ADUC_RootKeyPackage_Hash rootkeypkg_hash = { + SHA256, /* alg */ + hashPubKeyHandle /* hash */ + }; + + VECTOR_push_back(disallowedSigningPubKeyHashes, &rootkeypkg_hash, 1); + } + + return disallowedSigningPubKeyHashes; +} + +static std::string GetSJWKJson(const char* signing_key_N) +{ + const std::string sjwk_template{ R"( { )" + R"( "kty": "RSA", )" + R"( "alg": "RS256", )" + R"( "kid": "ADU.210609.R.S", )" + R"( "n": "<%MODULUS%>", )" + R"( "e": "AQAB" )" + R"( } )" }; + return std::regex_replace(sjwk_template, std::regex("<%MODULUS%>"), std::string{ signing_key_N }); +} + +TEST_CASE("IsSigningKeyDisallowed") +{ + SECTION("Missing - Empty list") + { + VECTOR_HANDLE disallowedSigningKeys = GetSigningKeyDisallowedList(nullptr); // empty vector + + std::string sjwk{ GetSJWKJson(AllowedSigningKey) }; // SJWK has allowed signing key + JWSResult jwsResult = IsSigningKeyDisallowed(sjwk.c_str(), disallowedSigningKeys); + + CHECK(jwsResult == JWSResult_Success); // Namely, it is not JWSResult_DisallowedSigningKey. + + VECTOR_destroy(disallowedSigningKeys); + } + + SECTION("Missing - Non-empty list") + { + VECTOR_HANDLE disallowedSigningKeys = GetSigningKeyDisallowedList(DisallowedSigningKey); + + std::string sjwk{ GetSJWKJson(AllowedSigningKey) }; + JWSResult jwsResult = IsSigningKeyDisallowed(sjwk.c_str(), disallowedSigningKeys); + + CHECK(jwsResult == JWSResult_Success); // Allowed is not Disallowed that is in the disallow list. + + VECTOR_destroy(disallowedSigningKeys); + } + + SECTION("sjwk key found in Disallow list") + { + VECTOR_HANDLE disallowedSigningKeys = GetSigningKeyDisallowedList(DisallowedSigningKey); + + std::string sjwk{ GetSJWKJson(DisallowedSigningKey) }; + JWSResult jwsResult = IsSigningKeyDisallowed(sjwk.c_str(), disallowedSigningKeys); + + CHECK(jwsResult == JWSResult_DisallowedSigningKey); // Disallowed signing key is enforced. + + VECTOR_destroy(disallowedSigningKeys); } } diff --git a/src/utils/jws_utils/tests/testdata/jws_utils/testrootkeypkg.json b/src/utils/jws_utils/tests/testdata/jws_utils/testrootkeypkg.json new file mode 100644 index 000000000..303c24d27 --- /dev/null +++ b/src/utils/jws_utils/tests/testdata/jws_utils/testrootkeypkg.json @@ -0,0 +1 @@ +{"protected":{"version":1,"published":1675972876,"disabledRootKeys":[],"disabledSigningKeys":[],"rootKeys":{"ADU.200702.R":{"keyType":"RSA","n":"1UIurxFUo1Blh6JNW7oa-6ky3-mZXwVFyK-9NR2J6CcnWKOo7sXFHk_3kqYSBn09fbAH9ix_3m0q9bxJvBXv8IHLP4hPJx2IcShgCLYZ0tI50AUfPHaGcbtZWLyxiHurVii_MXNEMhD9PdOWXP9OXLNr_4uEm4uAuEnQffrWQFh2TcByJ3XLmi-btJ8PJfEcxRsLWjB9L7jvpyZYU6_VHVUBUQ3pG6IPP9fpHSBBpuYUCq7-8hwq1uQEe_YUfuwPl4P6WPqBNiG5oyv62WELGpT3wb5_QBRKyfo1f-9mcACx_dvXYQ07WHRnlIl1dpZ8kYfSjhGX7nuHbJovRdhlP1JwmCrLyARj9clHz3D07WSndKUjj7bt9xzTsBxkVxJaqYGEH6DnUBmWtIKxrEjj4TKCy0AfrMRZvBA0UYL5KI2oHpv1eUV1styaEUMIvmHMmsTLdzb_g92ocU9Rjg57Tfp5mI2-_IJ-QEipEgGo2X7zpRvx-5B3PkCHGMmr2fd5","e":65537},"ADU.200703.R":{"keyType":"RSA","n":"sqOydBb6uyD5UnbmJz6AQcb-zzD5yJb1WQqqgedRg4rE9Rc6LyrmV9Rxzoo975pVdj6Z4sKuTO4tuHj1ok4o8pxOOWW87OQN5eM4qFmrCKQbtPSgUqM4s0YhE8w8aAbe_gCmkm7eTEcQ1hycJPXNcOH1anxoEx3hxfaoTyGfhnxExYqZHMXTBptacZ0JHMNkMWrFF5UdXSrxVcdm1Oj12albjKJsYmAFN9cysHPL90s2JyQhjDgKuBj-9RVgNYs17x4PiKYTjXt977PnsMmmHHB7zPIpi4f3vZ22iG-sc_9y8u9IJ5ZyhgaiXON9zrCe5cLZTsTzf3gHS2WIRQwR5ZZWNIgtFg5ZQtL32e0d7ck3d0R-44Q2n1gT72_kw0TUdwaKz1vIgByimGULNdxzyGnQXuglQ5722KsFr1EpI1VAWBDquOLNXXnM7N-0W5jH-uPSbCbOLixW4M-N7v2TEi8ASY0cgjhWpl15REoa89wWELPBLScR_huYBeSjYDGZ","e":65537}}},"signatures":[{"alg":"RS256","sig":"eW8Cn256fBmV0DfintpvKLKBJJ2estNVeBvriVcazxE0-R_eFfpA1lYFpaOTmVx1g8dcRFYCmCXnmqLcrEZFLRJ26GezCQxkMtgo5NhlzLAc5BhaWn4_HDx1Y1yObWvQf1ZYfMFIntEtCDYLK1DxmmtqFy-0uLBIC4vPXLCdW0g4sGlXskMt0caszgYSduHgAI6AicQqSGjAy6Sms3gWELR4xbSK765IDp4rWqXns_aLy8pbOgar4Uxusmz5ydmJ9p3epMIhthe1D_kNwhzg5egi5B_S3LgEbm5DiJwyewwNPdZH-xNzP4KhLUK0sZjXk21OE3pj5Ia-Eydkrm4K6puf_ZR1G_XwhLO8s0QKZnjYqIL_EldJdwcKnW6lZDOnkYYGb7NYYS8FxIP4AG8FannN0xD503fhd7bsyIQGaXEQwRZgV88oKQy_-EQFUZ2MvzAKq2Cg7_KoBFEfSmU5MZgPD-4OycU98bAtBVcK-3phFQPdtKPkqjaDqBF3pTK3"},{"alg":"RS256","sig":"Mj9AZXSqwu6NUWUvdLIbSMy--Yp68wWPOcsKSZ-9qToD0RIF7Q3rbgKCYC9FFzHzwBolBwsqZogHeEv0wGbj4EuCKRHrD1onc8AiBpUWD9QrySP8Ca3QzBeE1jDkGVJvmuYsviLzletYT-6GCEBBWuQyUSmbA0Az9x4sUg9BNF7M2_zyd4GGyHDSt9YVYJekv9IQwEinEUGW6wB8St_V3x4w1Pujl69azOI0VpTtXXTlw7xwyhq_gO4mCO40b8KBGdTdD1pHz_4UT4hHvoRl9nVRi4lKBCSEzpLr_Oqs2s7TwS13GEg-XMMkzd3jGVkFS9C9ezcJC8osaxg0i5z0g_lc785Rg1yXM-gytOYFn2xyWIzqvJ5CQn3XgkCO9lduYkEF78xHFNbsorup2c2GRZTdWpTwLEi0v6bv303CxhNMGJYiZull-lRVLANFVO_pewduE3DqDTs3PF2InX0m9_ve9XouDvooaw1q3Zk_BgNgcxQxSQv2ifP4EFrNvPg2"}]} diff --git a/src/utils/process_utils/src/process_utils.cpp b/src/utils/process_utils/src/process_utils.cpp index debd13286..5f66dbbe1 100644 --- a/src/utils/process_utils/src/process_utils.cpp +++ b/src/utils/process_utils/src/process_utils.cpp @@ -26,12 +26,8 @@ #include #include // for std::function -#include -#include #include -#include - #include #include diff --git a/src/utils/https_proxy_utils/CMakeLists.txt b/src/utils/reporting_utils/CMakeLists.txt similarity index 53% rename from src/utils/https_proxy_utils/CMakeLists.txt rename to src/utils/reporting_utils/CMakeLists.txt index 2ff5e5afd..262359222 100644 --- a/src/utils/https_proxy_utils/CMakeLists.txt +++ b/src/utils/reporting_utils/CMakeLists.txt @@ -1,19 +1,15 @@ -cmake_minimum_required (VERSION 3.5) +set (target_name reporting_utils) -set (target_name https_proxy_utils) +include (agentRules) +compileasc99 () -add_library (${target_name} STATIC src/https_proxy_utils.c) +add_library (${target_name} STATIC src/reporting_utils.c) add_library (aduc::${target_name} ALIAS ${target_name}) -# -# Turn -fPIC on, in order to use this library in another shared library. -# -set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) +target_link_aziotsharedutil (${target_name} PUBLIC) target_include_directories (${target_name} PUBLIC inc) -target_link_aziotsharedutil (${target_name} PUBLIC) - target_link_libraries ( ${target_name} PUBLIC aduc::c_utils diff --git a/src/utils/reporting_utils/inc/aduc/reporting_utils.h b/src/utils/reporting_utils/inc/aduc/reporting_utils.h new file mode 100644 index 000000000..cd3249c12 --- /dev/null +++ b/src/utils/reporting_utils/inc/aduc/reporting_utils.h @@ -0,0 +1,17 @@ +#ifndef ADUC_REPORTING_UTILS_H +#define ADUC_REPORTING_UTILS_H + +#include +#include +#include +#include +#include + +EXTERN_C_BEGIN + +STRING_HANDLE ADUC_ReportingUtils_CreateReportingErcHexStr(const int32_t erc, bool is_first); +STRING_HANDLE ADUC_ReportingUtils_StringHandleFromVectorInt32(VECTOR_HANDLE vec, size_t max); + +EXTERN_C_END + +#endif // ADUC_REPORTING_UTILS_H diff --git a/src/utils/reporting_utils/src/reporting_utils.c b/src/utils/reporting_utils/src/reporting_utils.c new file mode 100644 index 000000000..13026347d --- /dev/null +++ b/src/utils/reporting_utils/src/reporting_utils.c @@ -0,0 +1,57 @@ +#include "aduc/reporting_utils.h" +#include // size_t +#include // int32_t + +STRING_HANDLE ADUC_ReportingUtils_CreateReportingErcHexStr(const int32_t erc, bool is_first) +{ + return STRING_construct_sprintf(is_first ? "%08X" : ",%08X", erc); +} + +STRING_HANDLE ADUC_ReportingUtils_StringHandleFromVectorInt32(VECTOR_HANDLE vec, size_t max) +{ + bool failed = true; + + size_t vec_size = VECTOR_size(vec); + vec_size = vec_size < max ? vec_size : max; + + STRING_HANDLE suffix = NULL; + STRING_HANDLE delimited = STRING_new(); + if (delimited == NULL) + { + return NULL; + } + + for (size_t i = 0; i < vec_size; ++i) + { + int concat_result = 0; + const int32_t* erc = (int32_t*)VECTOR_element(vec, i); + + suffix = ADUC_ReportingUtils_CreateReportingErcHexStr(*erc, false /* is_first */); + if (suffix == NULL) + { + goto done; + } + + concat_result = STRING_concat_with_STRING(delimited, suffix); + STRING_delete(suffix); + suffix = NULL; + + if (concat_result != 0) + { + goto done; + } + } + + failed = false; +done: + + STRING_delete(suffix); + + if (failed) + { + STRING_delete(delimited); + return NULL; + } + + return delimited; +} diff --git a/src/utils/reporting_utils/tests/CMakeLists.txt b/src/utils/reporting_utils/tests/CMakeLists.txt new file mode 100644 index 000000000..c2e5e92e3 --- /dev/null +++ b/src/utils/reporting_utils/tests/CMakeLists.txt @@ -0,0 +1,18 @@ +project (reporting_utils_unit_tests) + +include (agentRules) +compileasc99 () +disablertti () + +find_package (Catch2 REQUIRED) + +add_executable (${PROJECT_NAME}) +target_sources (${PROJECT_NAME} PRIVATE main.cpp reporting_utils_ut.cpp) + +target_link_aziotsharedutil (${PROJECT_NAME} PRIVATE) +target_link_libraries (${PROJECT_NAME} PRIVATE aduc::c_utils aduc::reporting_utils + aduc::string_utils Catch2::Catch2) + +include (CTest) +include (Catch) +catch_discover_tests (${PROJECT_NAME}) diff --git a/src/utils/reporting_utils/tests/main.cpp b/src/utils/reporting_utils/tests/main.cpp new file mode 100644 index 000000000..c99fb6024 --- /dev/null +++ b/src/utils/reporting_utils/tests/main.cpp @@ -0,0 +1,9 @@ +/** + * @file main.cpp + * @brief reporting_utils tests main entry point. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#define CATCH_CONFIG_MAIN +#include diff --git a/src/utils/reporting_utils/tests/reporting_utils_ut.cpp b/src/utils/reporting_utils/tests/reporting_utils_ut.cpp new file mode 100644 index 000000000..0959ab85e --- /dev/null +++ b/src/utils/reporting_utils/tests/reporting_utils_ut.cpp @@ -0,0 +1,94 @@ +/** + * @file reporting_utils_ut.cpp + * @brief Unit Tests for c_utils library + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#include +using Catch::Matchers::Equals; +#include +#include +#include + +TEST_CASE("ADUC_ReportingUtils_StringHandleFromVectorInt32") +{ + SECTION("zero elements") + { + VECTOR_HANDLE extended_result_codes = VECTOR_create(sizeof(int32_t)); + REQUIRE(extended_result_codes != NULL); + + STRING_HANDLE delimited_str = ADUC_ReportingUtils_StringHandleFromVectorInt32(extended_result_codes, 4); + ADUC::StringUtils::STRING_HANDLE_wrapper wrapped{ delimited_str }; + CHECK(!wrapped.is_null()); + CHECK_THAT(STRING_c_str(wrapped.get()), Equals("")); + } + + SECTION("one element") + { + VECTOR_HANDLE extended_result_codes = VECTOR_create(sizeof(int32_t)); + REQUIRE(extended_result_codes != NULL); + + int32_t val = 0x00000001; + VECTOR_push_back(extended_result_codes, &val, 1); + + STRING_HANDLE delimited_str = ADUC_ReportingUtils_StringHandleFromVectorInt32(extended_result_codes, 4); + ADUC::StringUtils::STRING_HANDLE_wrapper wrapped{ delimited_str }; + CHECK(!wrapped.is_null()); + CHECK_THAT(STRING_c_str(wrapped.get()), Equals(",00000001")); + } + + SECTION("2 elements") + { + VECTOR_HANDLE extended_result_codes = VECTOR_create(sizeof(int32_t)); + REQUIRE(extended_result_codes != NULL); + + int32_t val = 0x00000001; + VECTOR_push_back(extended_result_codes, &val, 1); + + int32_t val2 = 0x00000002; + VECTOR_push_back(extended_result_codes, &val2, 1); + + STRING_HANDLE delimited_str = ADUC_ReportingUtils_StringHandleFromVectorInt32(extended_result_codes, 4); + ADUC::StringUtils::STRING_HANDLE_wrapper wrapped{ delimited_str }; + CHECK(!wrapped.is_null()); + CHECK_THAT(STRING_c_str(wrapped.get()), Equals(",00000001,00000002")); + } + + SECTION("max 1") + { + VECTOR_HANDLE extended_result_codes = VECTOR_create(sizeof(int32_t)); + REQUIRE(extended_result_codes != NULL); + + int32_t val = 0x00000001; + VECTOR_push_back(extended_result_codes, &val, 1); + + int32_t val2 = 0x00000002; + VECTOR_push_back(extended_result_codes, &val2, 1); + + STRING_HANDLE delimited_str = ADUC_ReportingUtils_StringHandleFromVectorInt32(extended_result_codes, 1); + ADUC::StringUtils::STRING_HANDLE_wrapper wrapped{ delimited_str }; + CHECK(!wrapped.is_null()); + CHECK_THAT(STRING_c_str(wrapped.get()), Equals(",00000001")); + } + + SECTION("max 2") + { + VECTOR_HANDLE extended_result_codes = VECTOR_create(sizeof(int32_t)); + REQUIRE(extended_result_codes != NULL); + + int32_t val = 0x00000001; + VECTOR_push_back(extended_result_codes, &val, 1); + + int32_t val2 = 0x00000002; + VECTOR_push_back(extended_result_codes, &val2, 1); + + int32_t val3 = 0x00000003; + VECTOR_push_back(extended_result_codes, &val3, 1); + + STRING_HANDLE delimited_str = ADUC_ReportingUtils_StringHandleFromVectorInt32(extended_result_codes, 2); + ADUC::StringUtils::STRING_HANDLE_wrapper wrapped{ delimited_str }; + CHECK(!wrapped.is_null()); + CHECK_THAT(STRING_c_str(wrapped.get()), Equals(",00000001,00000002")); + } +} diff --git a/src/utils/retry_utils/CMakeLists.txt b/src/utils/retry_utils/CMakeLists.txt index 54c2ae024..2f4ec794a 100644 --- a/src/utils/retry_utils/CMakeLists.txt +++ b/src/utils/retry_utils/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required (VERSION 3.5) +include (agentRules) + set (target_name retry_utils) add_library (${target_name} STATIC src/retry_utils.c) add_library (aduc::${target_name} ALIAS ${target_name}) @@ -12,12 +14,11 @@ target_include_directories (${target_name} PUBLIC ./inc ${ADUC_TYPES_INCLUDES} # set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) -find_package (azure_c_shared_utility REQUIRED) +target_link_aziotsharedutil (${target_name} PRIVATE) target_link_libraries ( ${target_name} PUBLIC aduc::adu_types - PRIVATE aduc::communication_abstraction - aduc::logging) + PRIVATE aduc::communication_abstraction aduc::logging) target_link_libraries (${target_name} PUBLIC libaducpal) diff --git a/src/utils/root_key_utils/CMakeLists.txt b/src/utils/root_key_utils/CMakeLists.txt new file mode 100644 index 000000000..f043eac2c --- /dev/null +++ b/src/utils/root_key_utils/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required (VERSION 3.5) + +set (target_name root_key_utils) + +include (agentRules) +compileasc99 () + +add_library (${target_name} STATIC) +add_library (aduc::${target_name} ALIAS ${target_name}) + +target_sources (${target_name} PRIVATE src/root_key_util.c src/root_key_list.c src/root_key_store.c) + +target_include_directories (${target_name} PUBLIC inc) + +target_link_aziotsharedutil (${target_name} PUBLIC) +find_package (umock_c REQUIRED CONFIG) + +# +# Turn -fPIC on, in order to use this library in another shared library. +# +set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_link_libraries ( + ${target_name} + PUBLIC aduc::c_utils aduc::crypto_utils aduc::rootkeypackage_utils umock_c + PRIVATE aduc::logging aduc::system_utils libaducpal) + +target_compile_definitions ( + ${target_name} PRIVATE ADUC_ROOTKEY_STORE_PACKAGE_PATH="${ADUC_ROOTKEY_STORE_PACKAGE_PATH}" + EMBED_TEST_ROOT_KEYS=${EMBED_TEST_ROOT_KEYS}) + +if (ADUC_BUILD_UNIT_TESTS) + add_subdirectory (tests) +endif () diff --git a/src/utils/root_key_utils/inc/root_key_list.h b/src/utils/root_key_utils/inc/root_key_list.h new file mode 100644 index 000000000..f16bcccc4 --- /dev/null +++ b/src/utils/root_key_utils/inc/root_key_list.h @@ -0,0 +1,29 @@ +/** + * @file root_key_list.h + * @brief Defines functions for getting the hardcoded root keys + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#include "aduc/c_utils.h" +#include + +#ifndef ROOT_KEY_LIST_H +# define ROOT_KEY_LIST_H + +EXTERN_C_BEGIN + +typedef struct tagRSARootKey +{ + const char* kid; + const char* N; + const unsigned int e; +} RSARootKey; + +MOCKABLE_FUNCTION(, const RSARootKey*, RootKeyList_GetHardcodedRsaRootKeys, ) + +MOCKABLE_FUNCTION(, size_t, RootKeyList_numHardcodedKeys, ) + +EXTERN_C_END + +#endif // ROOT_KEY_LIST_H diff --git a/src/utils/root_key_utils/inc/root_key_store.h b/src/utils/root_key_utils/inc/root_key_store.h new file mode 100644 index 000000000..4f4c7b531 --- /dev/null +++ b/src/utils/root_key_utils/inc/root_key_store.h @@ -0,0 +1,19 @@ +/** + * @file root_key_store.h + * @brief Defines the function for returning the path to the local store of the root key package + * @details Functions are mockable for testing purposes + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "aduc/c_utils.h" +#include +#ifndef ROOT_KEY_STORE_H +# define ROOT_KEY_STORE_H + +EXTERN_C_BEGIN + +MOCKABLE_FUNCTION(, const char*, RootKeyStore_GetRootKeyStorePath, ); + +EXTERN_C_END +#endif // ROOT_KEY_STORE_H diff --git a/src/utils/root_key_utils/inc/root_key_util.h b/src/utils/root_key_utils/inc/root_key_util.h new file mode 100644 index 000000000..4bdc3c34c --- /dev/null +++ b/src/utils/root_key_utils/inc/root_key_util.h @@ -0,0 +1,36 @@ +/** + * @file root_key_util.h + * @brief Defines the functions for getting, validating, and dealing with encoded and locally stored root keys + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "aduc/c_utils.h" +#include "aduc/result.h" +#include "aduc/rootkeypackage_types.h" +#include "crypto_key.h" +#include +#ifndef ROOT_KEY_UTIL_H +# define ROOT_KEY_UTIL_H + +EXTERN_C_BEGIN + +ADUC_Result RootKeyUtility_LoadPackageFromDisk( + ADUC_RootKeyPackage** rootKeyPackage, const char* fileLocation, bool validateSignatures); +ADUC_Result RootKeyUtility_ValidateRootKeyPackageWithHardcodedKeys(const ADUC_RootKeyPackage* rootKeyPackage); +ADUC_Result RootKeyUtility_WriteRootKeyPackageToFileAtomically( + const ADUC_RootKeyPackage* rootKeyPackage, const STRING_HANDLE fileDest); +ADUC_Result RootKeyUtility_ReloadPackageFromDisk(const char* filepath, bool validateSignatures); +ADUC_Result RootKeyUtility_LoadSerializedPackage(const char* fileLocation, char** outSerializePackage); +void RootKeyUtility_SetReportingErc(ADUC_Result_t erc); +void RootKeyUtility_ClearReportingErc(); +ADUC_Result_t RootKeyUtility_GetReportingErc(); +bool ADUC_RootKeyUtility_IsUpdateStoreNeeded(const STRING_HANDLE fileDest, const char* rootKeyPackageJsonString); +ADUC_Result RootKeyUtility_GetDisabledSigningKeys(VECTOR_HANDLE* outDisabledSigningKeyList); +bool RootKeyUtility_RootKeyIsDisabled(const ADUC_RootKeyPackage* rootKeyPackage, const char* keyId); + +ADUC_Result RootKeyUtility_GetKeyForKidFromHardcodedKeys(CryptoKeyHandle* key, const char* kid); +ADUC_Result RootKeyUtility_GetKeyForKid(CryptoKeyHandle* key, const char* kid); +EXTERN_C_END +#endif // ROOT_KEY_UTIL_H diff --git a/src/utils/root_key_utils/src/root_key_list.c b/src/utils/root_key_utils/src/root_key_list.c new file mode 100644 index 000000000..0f2f2e6c8 --- /dev/null +++ b/src/utils/root_key_utils/src/root_key_list.c @@ -0,0 +1,103 @@ +/** + * @file root_key_utility.c + * @brief Implements a static list of root keys used to verify keys and messages within crypto_lib and it's callers. + * these have exponents and parameters that have been extracted from their certs + * to ease the computation process but remain the same as the ones issued by the Authority + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#include "root_key_list.h" + +#include +#include +#include + +// +// Hardcoded Root Keychain Definitions +// + +// clang-format off +static const RSARootKey HardcodedRSARootKeyList[] = +{ +#if EMBED_TEST_ROOT_KEYS == 1 + { + "ADU.200702.R.T", + "ALnCgCTJLJFVSo7VSxXa2jEndHE2tlXJ3ZJXueNLJoN2tr-IWF6B1gWgNLZGY-VT" + "NX1kfl3IxyfTUYe-E87B6jyTg159PObVhjMDs1BD4TkgM0WmPhQq9t0iKjOgBwmD" + "8c4im8_ZBHA-ntON1MgkTMi3_H0Cd0jrwVwjaFUpIkPK8HA3h4xYks5PwS8tCRkY" + "38yWRfJfqtTflaqat1bTpkCaYW5Ui-mwvQEdRja72iWx4knImhb7ornJ3lQbtwem" + "2NMBIp9tMfwq40zZolhLbmP86FMSRixkFR5MyUUQEMHh8cPxQ0jHd1IYiDUbje0G" + "96_0vRz6BTZGb2jlFTlXu1lGNIwBSM1VBHKtgk8eN6dF72i3mBM_g7BvkZT5JE9o" + "vtcpBIcLSX7Chg0yD-Zjw7JWZE1EnIGRUTE6CXcDrRipAMxl0D5b7X9yC-PX1EzO" + "K_HaSHOxNTdg47feP_5HHWNXvCcX4ER-0aIkAgEx3qevpkFuVCqv6JyVtmzaO4vR" + "mw", + 65537 + }, + { + + "ADU.200703.R.T", + + "ANlorLkqFQ8yrM9NgZj9m7pVic8Kwx-IQSICms-CLYaJfy2DkqZNJJ6J7wohAeWW" + "_ZCjFAJTnSpbrztpxiqfeZKmc5u-7Yao1G3uW2chTgqj5Tx_tJ1B4YP6B171_-Ts" + "95fuyoTBtG1Fs0O9p5JlB1YnsQDwaWPruM2U0a_DDjWxrTCJ61SO0iU206Gdc8zP" + "m9OKPMMZTXzSbKY2Nj__NppiV2SpUZRnVri2C6Hl4SqLH0rvTD9Wi4wvqbhJmJmf" + "nbKDIN_wx4Zbgvu1Tdq_HQJt3t3Eyri92zbxoLk8E53HDBMNVcSzFLJ6bA7cRR43" + "m8KUVb7O-iSbFt35ZWGWdk9ZeVlsUG1gwnbou3Q75wHxMMOybscOHSnV55UqKwRm" + "ufkMWdDp3ykE2G0MHgPxnoZCjz75LvZsyvp9D8X7GkDC0tfiX14IlTUOHq4bv-tu" + "YihcFipX7qjrmVoiTJBUyvjQZqQygGgbcXR_-V4HN2QO0jMpslX8PvVJlr_qKCtR" + "fQ", + + 65537 + } +#else + { + "ADU.200702.R", + "ANVCLq8RVKNQZYeiTVu6GvupMt_pmV8FRcivvTUdiegnJ1ijqO7FxR5P95KmEgZ9" + "PX2wB_Ysf95tKvW8SbwV7_CByz-ITycdiHEoYAi2GdLSOdAFHzx2hnG7WVi8sYh7" + "q1YovzFzRDIQ_T3Tllz_Tlyza_-LhJuLgLhJ0H361kBYdk3Acid1y5ovm7SfDyXx" + "HMUbC1owfS-476cmWFOv1R1VAVEN6RuiDz_X6R0gQabmFAqu_vIcKtbkBHv2FH7s" + "D5eD-lj6gTYhuaMr-tlhCxqU98G-f0AUSsn6NX_vZnAAsf3b12ENO1h0Z5SJdXaW" + "fJGH0o4Rl-57h2yaL0XYZT9ScJgqy8gEY_XJR89w9O1kp3SlI4-27fcc07AcZFcS" + "WqmBhB-g51AZlrSCsaxI4-EygstAH6zEWbwQNFGC-SiNqB6b9XlFdbLcmhFDCL5h" + "zJrEy3c2_4PdqHFPUY4Oe036eZiNvvyCfkBIqRIBqNl-86Ub8fuQdz5AhxjJq9n3" + "eQ", + 65537 + }, + { + + "ADU.200703.R", + "ALKjsnQW-rsg-VJ25ic-gEHG_s8w-ciW9VkKqoHnUYOKxPUXOi8q5lfUcc6KPe-a" + "VXY-meLCrkzuLbh49aJOKPKcTjllvOzkDeXjOKhZqwikG7T0oFKjOLNGIRPMPGgG" + "3v4AppJu3kxHENYcnCT1zXDh9Wp8aBMd4cX2qE8hn4Z8RMWKmRzF0wabWnGdCRzD" + "ZDFqxReVHV0q8VXHZtTo9dmpW4yibGJgBTfXMrBzy_dLNickIYw4CrgY_vUVYDWL" + "Ne8eD4imE417fe-z57DJphxwe8zyKYuH972dtohvrHP_cvLvSCeWcoYGolzjfc6w" + "nuXC2U7E8394B0tliEUMEeWWVjSILRYOWULS99ntHe3JN3dEfuOENp9YE-9v5MNE" + "1HcGis9byIAcophlCzXcc8hp0F7oJUOe9tirBa9RKSNVQFgQ6rjizV15zOzftFuY" + "x_rj0mwmzi4sVuDPje79kxIvAEmNHII4VqZdeURKGvPcFhCzwS0nEf4bmAXko2Ax" + "mQ", + 65537 + } +#endif +}; +// clang-format on + +/** + * @brief Returns the hardcoded array of hardcoded RSARootKeys + * + * @return the current list of hardcoded keys + */ +const RSARootKey* RootKeyList_GetHardcodedRsaRootKeys(void) +{ + return HardcodedRSARootKeyList; +} + +/** + * @brief Returns the number of hardcoded RSARootKeys + * + * @return the current size of the list of hardcoded root keys + */ +size_t RootKeyList_numHardcodedKeys(void) +{ + return ARRAY_SIZE(HardcodedRSARootKeyList); +} diff --git a/src/utils/root_key_utils/src/root_key_store.c b/src/utils/root_key_utils/src/root_key_store.c new file mode 100644 index 000000000..4c89ba517 --- /dev/null +++ b/src/utils/root_key_utils/src/root_key_store.c @@ -0,0 +1,27 @@ +/** + * @file root_key_utility.c + * @brief Implements a static list of root keys used to verify keys and messages within crypto_lib and it's callers. + * these have exponents and parameters that have been extracted from their certs + * to ease the computation process but remain the same as the ones issued by the Authority + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#include "root_key_store.h" + +#include +#include +#include + +// +// Surfaces the hardcoded package path for the root key package +// + +#ifndef ADUC_ROOTKEY_STORE_PACKAGE_PATH +# error "ADUC_ROOTKEY_STORE_PACKAGE_PATH must be defined" +#endif + +const char* RootKeyStore_GetRootKeyStorePath() +{ + return ADUC_ROOTKEY_STORE_PACKAGE_PATH; +} diff --git a/src/utils/root_key_utils/src/root_key_util.c b/src/utils/root_key_utils/src/root_key_util.c new file mode 100644 index 000000000..08e547ea9 --- /dev/null +++ b/src/utils/root_key_utils/src/root_key_util.c @@ -0,0 +1,886 @@ +/** + * @file root_key_utility.c + * @brief Implements a static list of root keys used to verify keys and messages within crypto_lib and it's callers. + * these have exponents and parameters that have been extracted from their certs + * to ease the computation process but remain the same as the ones issued by the Authority + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "root_key_util.h" + +#include "aduc/rootkeypackage_parse.h" +#include "aduc/rootkeypackage_types.h" +#include "aduc/rootkeypackage_utils.h" +#include "aducpal/stdio.h" +#include "aducpal/strings.h" +#include "base64_utils.h" +#include "crypto_lib.h" +#include "root_key_list.h" +#include "root_key_store.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Root Key Validation Helper Functions +// + +static ADUC_RootKeyPackage* localStore = NULL; +ADUC_Result_t s_rootKeyErc = 0; + +/** + * @brief Helper function for making a CryptoKeyHandle from an ADUC_RootKey + * + * @param rootKey ADUC_RootKey to make into a crypto key handle + * @return NULL on failure, a CryptoKeyHandle on success + */ +CryptoKeyHandle MakeCryptoKeyHandleFromADUC_RootKey(const ADUC_RootKey* rootKey) +{ + if (rootKey == NULL) + { + return NULL; + } + + CryptoKeyHandle key = NULL; + + const CONSTBUFFER* modulus; + switch (rootKey->keyType) + { + case ADUC_RootKey_KeyType_RSA: + modulus = CONSTBUFFER_GetContent(rootKey->rsaParameters.n); + + key = RSAKey_ObjFromModulusBytesExponentInt(modulus->buffer, modulus->size, rootKey->rsaParameters.e); + break; + + case ADUC_RootKey_KeyType_INVALID: + break; + + default: + break; + } + + return key; +} + +/** + * @brief Makes a CryptoKeyHandle key from a rootkey of type RSARootKey + * + * @param rootKey one of the hardcoded RSA Rootkeys + * @return a pointer to a CryptoKeyHandle on success, null on failure + */ +CryptoKeyHandle MakeCryptoKeyHandleFromRSARootkey(const RSARootKey rootKey) +{ + CryptoKeyHandle key = NULL; + uint8_t* modulus = NULL; + + const size_t modulusSize = Base64URLDecode(rootKey.N, &modulus); + + if (modulusSize == 0) + { + goto done; + } + + key = RSAKey_ObjFromModulusBytesExponentInt(modulus, modulusSize, rootKey.e); + +done: + + free(modulus); + + return key; +} + +/** + * @brief Initializes an ADUC_RootKey with the parameters in an RSARootKey + * @details Caller must take care to de-init the rootKey using ADUC_RootKey_DeInit() + * @param rootKey rootKey pointer to initialize with the data + * @param rsaKey rsaKey to use for intiialization + * @return True on success; false on failure + */ +static bool InitializeADUC_RootKey_From_RSARootKey(ADUC_RootKey* rootKey, const RSARootKey* rsaKey) +{ + bool success = false; + STRING_HANDLE kid = NULL; + uint8_t* modulus = 0; + + if (rootKey == NULL || rsaKey == NULL || rsaKey->N == NULL || IsNullOrEmpty(rsaKey->kid)) + { + goto done; + } + + rootKey->keyType = ADUC_RootKey_KeyType_RSA; + + kid = STRING_construct(rsaKey->kid); + + if (kid == NULL) + { + goto done; + } + + rootKey->kid = kid; + + const size_t modulusSize = Base64URLDecode(rsaKey->N, &modulus); + + if (modulusSize == 0) + { + goto done; + } + + rootKey->rsaParameters.n = CONSTBUFFER_Create(modulus, modulusSize); + + if (rootKey->rsaParameters.n == NULL) + { + goto done; + } + + rootKey->rsaParameters.e = rsaKey->e; + + success = true; +done: + + if (!success) + { + ADUC_RootKey_DeInit(rootKey); + } + + return success; +} + +/** + * @brief Returns the index for the signature associated with the key + * + * @param foundIndex index that will be set with the index for the signature + * @param rootKeyPackage the root key package to search + * @param seekKid the kid to search for within the rootKeyPackage + * @return True on success; false on failure + */ +bool RootKeyUtility_GetSignatureForKey( + size_t* foundIndex, const ADUC_RootKeyPackage* rootKeyPackage, const char* seekKid) +{ + if (foundIndex == NULL || rootKeyPackage == NULL || seekKid == NULL) + { + return false; + } + + size_t numKeys = VECTOR_size(rootKeyPackage->protectedProperties.rootKeys); + + for (size_t i = 0; i < numKeys; ++i) + { + ADUC_RootKey* root_key = (ADUC_RootKey*)VECTOR_element(rootKeyPackage->protectedProperties.rootKeys, i); + + if (root_key == NULL) + { + return false; + } + + if (strcmp(STRING_c_str(root_key->kid), seekKid) == 0) + { + *foundIndex = i; + return true; + } + } + + return false; +} + +/** + * @brief Fills a VECTOR_HANDLE with the hardcoded root keys in ADUC_RootKey format + * @details Caller must free @p aducRootKeyVector using VECTOR_delete() + * @param aducRootKeyVector vector handle to initialize with the hard coded root keys + * @return True on sucess; false on failure + */ +bool RootKeyUtility_GetHardcodedKeysAsAducRootKeys(VECTOR_HANDLE* aducRootKeyVector) +{ + bool success = false; + + VECTOR_HANDLE tempHandle = VECTOR_create(sizeof(ADUC_RootKey)); + + if (tempHandle == NULL) + { + goto done; + } + + const RSARootKey* rsaKeyList = RootKeyList_GetHardcodedRsaRootKeys(); + + const size_t rsaKeyListSize = RootKeyList_numHardcodedKeys(); + + for (int i = 0; i < rsaKeyListSize; ++i) + { + RSARootKey key = rsaKeyList[i]; + + ADUC_RootKey rootKey = { .kid = NULL, + .keyType = ADUC_RootKey_KeyType_INVALID, + .rsaParameters = { .n = NULL, .e = 0 } }; + + if (!InitializeADUC_RootKey_From_RSARootKey(&rootKey, &key)) + { + goto done; + } + VECTOR_push_back(tempHandle, &rootKey, 1); + } + + if (VECTOR_size(tempHandle) == 0) + { + goto done; + } + + // + // Other key types can be added here + // + success = true; + +done: + + if (!success) + { + if (tempHandle != NULL) + { + const size_t tempHandleSize = VECTOR_size(tempHandle); + for (size_t i = 0; i < tempHandleSize; ++i) + { + ADUC_RootKey* rootKey = VECTOR_element(tempHandle, i); + + ADUC_RootKey_DeInit(rootKey); + } + VECTOR_destroy(tempHandle); + tempHandle = NULL; + } + } + + *aducRootKeyVector = tempHandle; + + return success; +} + +/** + * @brief Validates the @p rootKeyPackage using a RSARootKEy + * @details Helper function for RootKeyUtility_ValidateRootKeyPackageWithHardcodedKeys(). It explicitly does not check for disabled root keys. + * @param rootKeyPackage package to be validated + * @param rootKey the RSARootKey to be used for validation + * @return a value of ADUC_Result + */ +ADUC_Result RootKeyUtility_ValidatePackageWithKey(const ADUC_RootKeyPackage* rootKeyPackage, const RSARootKey rootKey) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + CryptoKeyHandle rootKeyCryptoKey = NULL; + + if (rootKeyPackage == NULL) + { + goto done; + } + + size_t signatureIndex = 0; + if (!RootKeyUtility_GetSignatureForKey(&signatureIndex, rootKeyPackage, rootKey.kid)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_FOR_KEY_NOT_FOUND; + goto done; + } + + // Get the signature + ADUC_RootKeyPackage_Hash* signature = + (ADUC_RootKeyPackage_Hash*)VECTOR_element(rootKeyPackage->signatures, signatureIndex); + + if (signature == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_UNEXPECTED; + goto done; + } + + rootKeyCryptoKey = MakeCryptoKeyHandleFromRSARootkey(rootKey); + + if (rootKeyCryptoKey == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_UNEXPECTED; + goto done; + } + + const char* protectedProperties = STRING_c_str(rootKeyPackage->protectedPropertiesJsonString); + const size_t protectedPropertiesLength = STRING_length(rootKeyPackage->protectedPropertiesJsonString); + + const CONSTBUFFER* signatureHash = CONSTBUFFER_GetContent(signature->hash); + + if (!CryptoUtils_IsValidSignature( + CRYPTO_UTILS_SIGNATURE_VALIDATION_ALG_RS256, + signatureHash->buffer, + signatureHash->size, + (const uint8_t*)protectedProperties, + protectedPropertiesLength, + rootKeyCryptoKey)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_VALIDATION_FAILED; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + + if (rootKeyCryptoKey != NULL) + { + CryptoUtils_FreeCryptoKeyHandle(rootKeyCryptoKey); + } + + return result; +} + +/** + * @brief Validates the @p rootKeyPackage using the hard coded root keys from the RootKeyList within the agent binary + * + * @param rootKeyPackage root key package containing the signatures to validate with the hardcoded root keys + * @return a value of ADUC_Result + */ +ADUC_Result RootKeyUtility_ValidateRootKeyPackageWithHardcodedKeys(const ADUC_RootKeyPackage* rootKeyPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + VECTOR_HANDLE hardcodedRootKeys = NULL; + + const RSARootKey* hardcodedRsaKeys = RootKeyList_GetHardcodedRsaRootKeys(); + const size_t numHardcodedKeys = RootKeyList_numHardcodedKeys(); + if (hardcodedRsaKeys == NULL || numHardcodedKeys == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_HARDCODED_ROOTKEY_LOAD_FAILED; + goto done; + } + + for (size_t i = 0; i < numHardcodedKeys; ++i) + { + const RSARootKey rootKey = hardcodedRsaKeys[i]; + + ADUC_Result validationResult = RootKeyUtility_ValidatePackageWithKey(rootKeyPackage, rootKey); + + if (IsAducResultCodeFailure(validationResult.ResultCode)) + { + result = validationResult; + goto done; + } + } + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + + if (hardcodedRootKeys != NULL) + { + const size_t hardcodedRootKeysLength = VECTOR_size(hardcodedRootKeys); + for (size_t i = 0; i < hardcodedRootKeysLength; ++i) + { + ADUC_RootKey* rootKey = (ADUC_RootKey*)VECTOR_element(hardcodedRootKeys, i); + + ADUC_RootKey_DeInit(rootKey); + } + VECTOR_destroy(hardcodedRootKeys); + } + + return result; +} + +/** + * @brief Writes the package @p rootKeyPackage to file location @p fileDest atomically + * @details creates a temp file with the content of @p rootKeyPackage and renames it to @p fileDest + * @param rootKeyPackage the root key package to be written to the file + * @param fileDest the destination for the file + * @return a value of ADUC_Result + */ +ADUC_Result RootKeyUtility_WriteRootKeyPackageToFileAtomically( + const ADUC_RootKeyPackage* rootKeyPackage, const STRING_HANDLE fileDest) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + JSON_Value* rootKeyPackageValue = NULL; + + char* rootKeyPackageSerializedString = NULL; + STRING_HANDLE tempFileName = NULL; + + if (rootKeyPackage == NULL || fileDest == NULL || STRING_length(fileDest) == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_BAD_ARGS; + goto done; + } + + rootKeyPackageSerializedString = ADUC_RootKeyPackageUtils_SerializePackageToJsonString(rootKeyPackage); + + if (rootKeyPackageSerializedString == NULL) + { + goto done; + } + + rootKeyPackageValue = json_parse_string(rootKeyPackageSerializedString); + + if (rootKeyPackageValue == NULL) + { + goto done; + } + + tempFileName = STRING_construct_sprintf("%s-temp", STRING_c_str(fileDest)); + + if (tempFileName == NULL) + { + goto done; + } + + if (json_serialize_to_file(rootKeyPackageValue, STRING_c_str(tempFileName)) != JSONSuccess) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANNOT_WRITE_PACKAGE_TO_STORE; + goto done; + } + + int ret = ADUCPAL_rename(STRING_c_str(tempFileName), STRING_c_str(fileDest)); + if (ret != 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_RENAME_TO_STORE; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + + if (rootKeyPackageSerializedString != NULL) + { + free(rootKeyPackageSerializedString); + } + + if (rootKeyPackageValue != NULL) + { + json_value_free(rootKeyPackageValue); + } + + if (tempFileName != NULL) + { + if (ADUC_SystemUtils_Exists(STRING_c_str(tempFileName))) + { + if (remove(STRING_c_str(tempFileName)) != 0) + { + Log_Info( + "RootKeyUtility_WriteRootKeyPackageToFileAtomically failed to remove temp file at %s", + STRING_c_str(tempFileName)); + } + } + + STRING_delete(tempFileName); + } + + return result; +} + +/** + * @brief Reloads the package from disk into the local store + * + * @param filepath The path to the package on disk, or use the default with NULL. + * @param validateSignatures Whether to validate root key pkg signatures. + * @return a value of ADUC_Result + */ +ADUC_Result RootKeyUtility_ReloadPackageFromDisk(const char* filepath, bool validateSignatures) +{ + if (localStore != NULL) + { + ADUC_RootKeyPackageUtils_Destroy(localStore); + free(localStore); + localStore = NULL; + } + + return RootKeyUtility_LoadPackageFromDisk( + &localStore, filepath == NULL ? ADUC_ROOTKEY_STORE_PACKAGE_PATH : filepath, validateSignatures); +} + +/** + * @brief Loads the RootKeyPackage from disk at file location @p fileLocation + * + * @param rootKeyPackage the address of the pointer to the root key package to be set + * @param fileLocation the file location to read the data from + * @param validateSignatures whether to validate the package with hard-coded keys + * @return a value of ADUC_Result + */ +ADUC_Result RootKeyUtility_LoadPackageFromDisk( + ADUC_RootKeyPackage** rootKeyPackage, const char* fileLocation, bool validateSignatures) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + ADUC_Result tmpResult = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + JSON_Value* rootKeyPackageValue = NULL; + + ADUC_RootKeyPackage* tempPkg = NULL; + + char* rootKeyPackageJsonString = NULL; + + if (fileLocation == NULL || rootKeyPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_BAD_ARGS; + goto done; + } + + tmpResult = RootKeyUtility_LoadSerializedPackage(fileLocation, &rootKeyPackageJsonString); + if (IsAducResultCodeFailure(tmpResult.ResultCode)) + { + result = tmpResult; + goto done; + } + + tempPkg = (ADUC_RootKeyPackage*)malloc(sizeof(ADUC_RootKeyPackage)); + + if (tempPkg == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_ERRNOMEM; + goto done; + } + + memset(tempPkg, 0, sizeof(*tempPkg)); + + ADUC_Result parseResult = ADUC_RootKeyPackageUtils_Parse(rootKeyPackageJsonString, tempPkg); + + if (IsAducResultCodeFailure(parseResult.ResultCode)) + { + result = parseResult; + goto done; + } + + if (validateSignatures) + { + ADUC_Result validationResult = RootKeyUtility_ValidateRootKeyPackageWithHardcodedKeys(tempPkg); + + if (IsAducResultCodeFailure(validationResult.ResultCode)) + { + result = validationResult; + goto done; + } + } + + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + ADUC_RootKeyPackageUtils_Destroy(tempPkg); + free(tempPkg); + tempPkg = NULL; + } + + if (rootKeyPackageValue != NULL) + { + json_value_free(rootKeyPackageValue); + } + + free(rootKeyPackageJsonString); + + *rootKeyPackage = tempPkg; + + return result; +} + +/** + * @brief Checks if the rootkey represented by @p keyId is in the disabledRootKeys of @p rootKeyPackage + * + * @param keyId the id of the key to check + * @return true if the key is in the disabledKeys section, false if it isn't + */ +bool RootKeyUtility_RootKeyIsDisabled(const ADUC_RootKeyPackage* rootKeyPackage, const char* keyId) +{ + if (rootKeyPackage == NULL) + { + return true; + } + + const size_t numDisabledKeys = VECTOR_size(rootKeyPackage->protectedProperties.disabledRootKeys); + + for (size_t i = 0; i < numDisabledKeys; ++i) + { + STRING_HANDLE* disabledKey = VECTOR_element(rootKeyPackage->protectedProperties.disabledRootKeys, i); + + if (strcmp(STRING_c_str(*disabledKey), keyId) == 0) + { + return true; + } + } + + return false; +} + +/** + * @brief Searches the local store for the key with the keyId @p keyId and returns it as a CryptoKeyHandle + * + * @param keyId the keyId for the root key to look for + * @return the CryptoKeyHandle associated with the keyId on success; NULL on failure + */ +CryptoKeyHandle RootKeyUtility_SearchLocalStoreForKey(const char* keyId) +{ + CryptoKeyHandle key = NULL; + + if (localStore == NULL) + { + return key; + } + + const size_t numStoreRootKeys = VECTOR_size(localStore->protectedProperties.rootKeys); + + for (size_t i = 0; i < numStoreRootKeys; ++i) + { + ADUC_RootKey* rootKey = VECTOR_element(localStore->protectedProperties.rootKeys, i); + + if (strcmp(STRING_c_str(rootKey->kid), keyId) == 0 && !RootKeyUtility_RootKeyIsDisabled(localStore, keyId)) + { + key = MakeCryptoKeyHandleFromADUC_RootKey(rootKey); + } + } + + return key; +} + +/** + * @brief GEts the key for @p keyId from the local store and allocates @p key + * @details the caller must free key using CryptoUtils_FreeCryptoKeyHandle() on key + * @param key the handle to allocate the CryptoKeyHandle for @p kid + * @param keyId + * @return ADUC_Result + */ +ADUC_Result RootKeyUtility_GetKeyForKeyIdFromLocalStore(CryptoKeyHandle* key, const char* keyId) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + CryptoKeyHandle tempKey = NULL; + + tempKey = RootKeyUtility_SearchLocalStoreForKey(keyId); + + if (tempKey == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_NO_ROOTKEY_FOUND_FOR_KEYID; + goto done; + } + + *key = tempKey; + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + + return result; +} +/** + * @brief Gets the key for @p kid from the hardcoded keys and allocates @p key + * @details this was made to expose root keys to the agent ONLY for very specific cases. Think carefully before you use this instead of RootKeyUtility_GetKeyForKid + * @param key the handle to allocate the CryptoKeyHandle for @p kid + * @param kid the key identifier associated with the key + * @return a value of ADUC_Result + */ +ADUC_Result RootKeyUtility_GetKeyForKidFromHardcodedKeys(CryptoKeyHandle* key, const char* kid) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + CryptoKeyHandle tempKey = NULL; + + const RSARootKey* hardcodedRsaRootKeys = RootKeyList_GetHardcodedRsaRootKeys(); + + const size_t numberKeys = RootKeyList_numHardcodedKeys(); + for (size_t i = 0; i < numberKeys; ++i) + { + if (strcmp(hardcodedRsaRootKeys[i].kid, kid) == 0) + { + tempKey = MakeCryptoKeyHandleFromRSARootkey(hardcodedRsaRootKeys[i]); + break; + } + } + + if (tempKey == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_NO_ROOTKEY_FOUND_FOR_KEYID; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + + *key = tempKey; + + return result; +} + +/** + * @brief Helper function that returns a CryptoKeyHandle associated with the kid + * @details The caller must free the returned Key with the CryptoUtils_FreeCryptoKeyHandle() function + * @param key the handle to allocate the CryptoKeyHandle for @p kid + * @param kid the key identifier associated with the key + * @param useOnlyHardcodedKeys this is used when the caller explicitly only wants hardcoded keys. This ignores checks for disabled hardcoded keys. + * @returns a value of ADUC_Result + */ +ADUC_Result RootKeyUtility_GetKeyForKid(CryptoKeyHandle* key, const char* kid) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + CryptoKeyHandle tempKey = NULL; + + RootKeyUtility_GetKeyForKidFromHardcodedKeys(&tempKey, kid); + + if (localStore == NULL) + { + const char* rootKeyStorePath = RootKeyStore_GetRootKeyStorePath(); + ADUC_Result loadResult = + RootKeyUtility_LoadPackageFromDisk(&localStore, rootKeyStorePath, true /* validateSignatures */); + + if (IsAducResultCodeFailure(loadResult.ResultCode)) + { + result = loadResult; + goto done; + } + } + + if (RootKeyUtility_RootKeyIsDisabled(localStore, kid)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNING_ROOTKEY_IS_DISABLED; + goto done; + } + + if (tempKey == NULL) + { + ADUC_Result fetchResult = RootKeyUtility_GetKeyForKeyIdFromLocalStore(&tempKey, kid); + + if (IsAducResultCodeFailure(fetchResult.ResultCode)) + { + result = fetchResult; + goto done; + } + } + + if (tempKey == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_NO_ROOTKEY_FOUND_FOR_KEYID; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; +done: + + *key = tempKey; + + return result; +} + +ADUC_Result RootKeyUtility_LoadSerializedPackage(const char* fileLocation, char** outSerializePackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + JSON_Value* rootKeyPackageValue = json_parse_file(fileLocation); + char* rootKeyPackageJsonString = NULL; + + if (rootKeyPackageValue == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_LOAD_FROM_STORE; + goto done; + } + + rootKeyPackageJsonString = json_serialize_to_string(rootKeyPackageValue); + + if (rootKeyPackageJsonString == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_FAILED_SERIALIZE_TO_STRING; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; + *outSerializePackage = rootKeyPackageJsonString; + rootKeyPackageJsonString = NULL; +done: + + free(rootKeyPackageJsonString); + + return result; +} + +void RootKeyUtility_SetReportingErc(ADUC_Result_t erc) +{ + s_rootKeyErc = erc; +} + +void RootKeyUtility_ClearReportingErc() +{ + s_rootKeyErc = 0; +} + +ADUC_Result_t RootKeyUtility_GetReportingErc() +{ + return s_rootKeyErc; +} + +bool ADUC_RootKeyUtility_IsUpdateStoreNeeded(const STRING_HANDLE storePath, const char* rootKeyPackageJsonString) +{ + bool update_needed = true; + char* storePackageJsonString = NULL; + + JSON_Value* storePkgJsonValue = json_parse_file(STRING_c_str(storePath)); + + if (storePkgJsonValue == NULL) + { + goto done; + } + + storePackageJsonString = json_serialize_to_string(storePkgJsonValue); + + if (storePackageJsonString == NULL) + { + goto done; + } + + if (strcmp(storePackageJsonString, rootKeyPackageJsonString) == 0) + { + update_needed = false; + } + +done: + free(storePackageJsonString); + + return update_needed; +} + +ADUC_Result RootKeyUtility_GetDisabledSigningKeys(VECTOR_HANDLE* outDisabledSigningKeyList) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + VECTOR_HANDLE disabledSigningKeyList = NULL; + + if (localStore == NULL) + { + ADUC_Result loadResult = RootKeyUtility_LoadPackageFromDisk( + &localStore, ADUC_ROOTKEY_STORE_PACKAGE_PATH, true /* validateSignatures */); + + if (IsAducResultCodeFailure(loadResult.ResultCode)) + { + Log_Error("Fail load pkg from disk: 0x%08x", loadResult.ExtendedResultCode); + result = loadResult; + goto done; + } + } + + disabledSigningKeyList = VECTOR_create(sizeof(ADUC_RootKeyPackage_Signature)); + if (disabledSigningKeyList == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + for (size_t i = 0; i < VECTOR_size(localStore->protectedProperties.disabledSigningKeys); ++i) + { + if (VECTOR_push_back( + disabledSigningKeyList, VECTOR_element(localStore->protectedProperties.disabledSigningKeys, i), 1) + != 0) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + } + + *outDisabledSigningKeyList = disabledSigningKeyList; + disabledSigningKeyList = NULL; + result.ResultCode = ADUC_GeneralResult_Success; + +done: + if (disabledSigningKeyList != NULL) + { + VECTOR_destroy(disabledSigningKeyList); + disabledSigningKeyList = NULL; + } + + return result; +} diff --git a/src/utils/root_key_utils/tests/CMakeLists.txt b/src/utils/root_key_utils/tests/CMakeLists.txt new file mode 100644 index 000000000..9416b0d46 --- /dev/null +++ b/src/utils/root_key_utils/tests/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required (VERSION 3.5) + +project (root_key_utils_ut) + +include (agentRules) + +compileasc99 () +disablertti () + +find_package (Catch2 REQUIRED) +find_package (umock_c REQUIRED CONFIG) + +set (sources main.cpp root_key_utils_ut.cpp) + +add_executable (${PROJECT_NAME}) + +target_sources (${PROJECT_NAME} PRIVATE main.cpp root_key_utils_ut.cpp) + +target_compile_definitions (${PROJECT_NAME} + PRIVATE ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}") + +target_link_libraries (${PROJECT_NAME} PRIVATE aduc::root_key_utils aduc::rootkeypackage_utils + aduc::string_utils Catch2::Catch2 umock_c) + +include (CTest) +include (Catch) +catch_discover_tests (${PROJECT_NAME}) diff --git a/src/utils/root_key_utils/tests/main.cpp b/src/utils/root_key_utils/tests/main.cpp new file mode 100644 index 000000000..1d0d2e421 --- /dev/null +++ b/src/utils/root_key_utils/tests/main.cpp @@ -0,0 +1,40 @@ +/** + * @file main.cpp + * @brief crypto_utils tests main entry point. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#define CATCH_CONFIG_RUNNER +#include + +// https://github.com/Azure/umock-c/blob/master/doc/umock_c.md +#include + +#include + +int main(int argc, char* argv[]) +{ + int result; + + // Global setup + result = umock_c_init([](UMOCK_C_ERROR_CODE error_code) -> void { + std::cout << "*** umock_c failed, err=" << error_code << std::endl; + }); + if (result != 0) + { + std::cout << "umock_c_init_failed, err=" << result << std::endl; + return result; + } + + result = Catch::Session().run(argc, argv); + if (result != 0) + { + std::cout << "Catch session failed, err=" << result << std::endl; + } + + // Global cleanup. + umock_c_deinit(); + + return result; +} diff --git a/src/utils/root_key_utils/tests/root_key_utils_signing_key_ut.cpp b/src/utils/root_key_utils/tests/root_key_utils_signing_key_ut.cpp new file mode 100644 index 000000000..3c473bc48 --- /dev/null +++ b/src/utils/root_key_utils/tests/root_key_utils_signing_key_ut.cpp @@ -0,0 +1,88 @@ +/** + * @file root_key_signing_key_utils_ut.cpp + * @brief Unit Tests for disabled signing keys in the root_key_utils library + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "root_key_util.h" +#include +#include +#include + +using Catch::Matchers::Equals; + +// Format of JWK payload: +// { +// "kty": "RSA", +// "alg": "RS256", +// "kid": "ADU.210609.R.S" +// "n": "", +// "e": "AQAB", +// } +const char[] decodedSigningKeyPayload = + R"( { )" + R"( "kty": "RSA", )" + R"( "alg": "RS256", )" + R"( "kid": "ADU.201609.R.S", )" + R"( "e": "AQAB", )" + R"( "n": "lLfsKo8Ytbcc2Q3N50UtLIfWQLVSAEbch+F/ce7S1YrJhXOSrzSfCnLpUiqPTw4zX/tiArAEuy7DAeUnEHEcx7Nkwwy5/8zKejvcEXpAJ/e3BKG4E4onfHQEpOsxwOKEeG0Gv9wWL3zTcNvdKXODXF3UPeJ1oGbPQms2zmCJxBbtSIYItmvicx2ekdVzWFw/vKTNuKk8hqK7HRfjOUKuKXyc+yHQI0aFBr2zkk3xh1tEOK98WJfxbcjPsDO6gzYzkXzCMza0O0GibBgLATT9Mf8YPpYG2jvOaDUoCQn2UcURNdl8hJbyjnZo2Jr+U84yuqOk7F4ZySoBv4bXJH2ZRRZFh/uSlsV9wRmYhYrv91DZiqk8HR6DSlnfneu28FThEmmosUM3k2YLsBc4Boupt3yaH8YnJT74u33uz19/MzTujKg7Tai12+XbtnZD9jTGayJtlhFeW+HC57AtAFZhqYwyGkX+83AaPXZ4a1O8u23NUGu2Ap7oM1N0yBJ+IlOz", )" + R"( } )"; + +// public key E and N +const char pubkey_exponent = "AQAB"; +const char pubkey_modulus = + "lLfsKo8Ytbcc2Q3N50UtLIfWQLVSAEbch+F/ce7S1YrJhXOSrzSfCnLpUiqPTw4zX/tiArAEuy7DAeUnEHEcx7Nkwwy5/8zKejvcEXpAJ/e3BKG4E4onfHQEpOsxwOKEeG0Gv9wWL3zTcNvdKXODXF3UPeJ1oGbPQms2zmCJxBbtSIYItmvicx2ekdVzWFw/vKTNuKk8hqK7HRfjOUKuKXyc+yHQI0aFBr2zkk3xh1tEOK98WJfxbcjPsDO6gzYzkXzCMza0O0GibBgLATT9Mf8YPpYG2jvOaDUoCQn2UcURNdl8hJbyjnZo2Jr+U84yuqOk7F4ZySoBv4bXJH2ZRRZFh/uSlsV9wRmYhYrv91DZiqk8HR6DSlnfneu28FThEmmosUM3k2YLsBc4Boupt3yaH8YnJT74u33uz19/MzTujKg7Tai12+XbtnZD9jTGayJtlhFeW+HC57AtAFZhqYwyGkX+83AaPXZ4a1O8u23NUGu2Ap7oM1N0yBJ+IlOz"; + +// raw bytes of PublicKey +unsigned char pubKey[] = { + 0x30, 0x82, 0x01, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0x94, 0xb7, 0xec, 0x2a, 0x8f, + 0x18, 0xb5, 0xb7, 0x1c, 0xd9, 0x0d, 0xcd, 0xe7, 0x45, 0x2d, 0x2c, 0x87, 0xd6, 0x40, 0xb5, 0x52, 0x00, 0x46, 0xdc, + 0x87, 0xe1, 0x7f, 0x71, 0xee, 0xd2, 0xd5, 0x8a, 0xc9, 0x85, 0x73, 0x92, 0xaf, 0x34, 0x9f, 0x0a, 0x72, 0xe9, 0x52, + 0x2a, 0x8f, 0x4f, 0x0e, 0x33, 0x5f, 0xfb, 0x62, 0x02, 0xb0, 0x04, 0xbb, 0x2e, 0xc3, 0x01, 0xe5, 0x27, 0x10, 0x71, + 0x1c, 0xc7, 0xb3, 0x64, 0xc3, 0x0c, 0xb9, 0xff, 0xcc, 0xca, 0x7a, 0x3b, 0xdc, 0x11, 0x7a, 0x40, 0x27, 0xf7, 0xb7, + 0x04, 0xa1, 0xb8, 0x13, 0x8a, 0x27, 0x7c, 0x74, 0x04, 0xa4, 0xeb, 0x31, 0xc0, 0xe2, 0x84, 0x78, 0x6d, 0x06, 0xbf, + 0xdc, 0x16, 0x2f, 0x7c, 0xd3, 0x70, 0xdb, 0xdd, 0x29, 0x73, 0x83, 0x5c, 0x5d, 0xd4, 0x3d, 0xe2, 0x75, 0xa0, 0x66, + 0xcf, 0x42, 0x6b, 0x36, 0xce, 0x60, 0x89, 0xc4, 0x16, 0xed, 0x48, 0x86, 0x08, 0xb6, 0x6b, 0xe2, 0x73, 0x1d, 0x9e, + 0x91, 0xd5, 0x73, 0x58, 0x5c, 0x3f, 0xbc, 0xa4, 0xcd, 0xb8, 0xa9, 0x3c, 0x86, 0xa2, 0xbb, 0x1d, 0x17, 0xe3, 0x39, + 0x42, 0xae, 0x29, 0x7c, 0x9c, 0xfb, 0x21, 0xd0, 0x23, 0x46, 0x85, 0x06, 0xbd, 0xb3, 0x92, 0x4d, 0xf1, 0x87, 0x5b, + 0x44, 0x38, 0xaf, 0x7c, 0x58, 0x97, 0xf1, 0x6d, 0xc8, 0xcf, 0xb0, 0x33, 0xba, 0x83, 0x36, 0x33, 0x91, 0x7c, 0xc2, + 0x33, 0x36, 0xb4, 0x3b, 0x41, 0xa2, 0x6c, 0x18, 0x0b, 0x01, 0x34, 0xfd, 0x31, 0xff, 0x18, 0x3e, 0x96, 0x06, 0xda, + 0x3b, 0xce, 0x68, 0x35, 0x28, 0x09, 0x09, 0xf6, 0x51, 0xc5, 0x11, 0x35, 0xd9, 0x7c, 0x84, 0x96, 0xf2, 0x8e, 0x76, + 0x68, 0xd8, 0x9a, 0xfe, 0x53, 0xce, 0x32, 0xba, 0xa3, 0xa4, 0xec, 0x5e, 0x19, 0xc9, 0x2a, 0x01, 0xbf, 0x86, 0xd7, + 0x24, 0x7d, 0x99, 0x45, 0x16, 0x45, 0x87, 0xfb, 0x92, 0x96, 0xc5, 0x7d, 0xc1, 0x19, 0x98, 0x85, 0x8a, 0xef, 0xf7, + 0x50, 0xd9, 0x8a, 0xa9, 0x3c, 0x1d, 0x1e, 0x83, 0x4a, 0x59, 0xdf, 0x9d, 0xeb, 0xb6, 0xf0, 0x54, 0xe1, 0x12, 0x69, + 0xa8, 0xb1, 0x43, 0x37, 0x93, 0x66, 0x0b, 0xb0, 0x17, 0x38, 0x06, 0x8b, 0xa9, 0xb7, 0x7c, 0x9a, 0x1f, 0xc6, 0x27, + 0x25, 0x3e, 0xf8, 0xbb, 0x7d, 0xee, 0xcf, 0x5f, 0x7f, 0x33, 0x34, 0xee, 0x8c, 0xa8, 0x3b, 0x4d, 0xa8, 0xb5, 0xdb, + 0xe5, 0xdb, 0xb6, 0x76, 0x43, 0xf6, 0x34, 0xc6, 0x6b, 0x22, 0x6d, 0x96, 0x11, 0x5e, 0x5b, 0xe1, 0xc2, 0xe7, 0xb0, + 0x2d, 0x00, 0x56, 0x61, 0xa9, 0x8c, 0x32, 0x1a, 0x45, 0xfe, 0xf3, 0x70, 0x1a, 0x3d, 0x76, 0x78, 0x6b, 0x53, 0xbc, + 0xbb, 0x6d, 0xcd, 0x50, 0x6b, 0xb6, 0x02, 0x9e, 0xe8, 0x33, 0x53, 0x74, 0xc8, 0x12, 0x7e, 0x22, 0x53, 0xb3, 0x02, + 0x03, 0x01, 0x00, 0x01 +}; + +// base64 URL of PublicKey: +const char pubkey = + "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAlLfsKo8Ytbcc2Q3N50UtLIfWQLVSAEbch-F_ce7S1YrJhXOSrzSfCnLpUiqPTw4zX_tiArAEuy7DAeUnEHEcx7Nkwwy5_8zKejvcEXpAJ_e3BKG4E4onfHQEpOsxwOKEeG0Gv9wWL3zTcNvdKXODXF3UPeJ1oGbPQms2zmCJxBbtSIYItmvicx2ekdVzWFw_vKTNuKk8hqK7HRfjOUKuKXyc-yHQI0aFBr2zkk3xh1tEOK98WJfxbcjPsDO6gzYzkXzCMza0O0GibBgLATT9Mf8YPpYG2jvOaDUoCQn2UcURNdl8hJbyjnZo2Jr-U84yuqOk7F4ZySoBv4bXJH2ZRRZFh_uSlsV9wRmYhYrv91DZiqk8HR6DSlnfneu28FThEmmosUM3k2YLsBc4Boupt3yaH8YnJT74u33uz19_MzTujKg7Tai12-XbtnZD9jTGayJtlhFeW-HC57AtAFZhqYwyGkX-83AaPXZ4a1O8u23NUGu2Ap7oM1N0yBJ-IlOzAgMBAAE"; + +// SHA256 HASH of public key: +const char sha256_hash_pubkey = "Y0jA4rDItwp5NIZYPUP8jAQoXIRPSKCDo4xtiWjyvig"; + +bool matches_pubkey(const CONSTBUFFER* buf) +{ + if (buf->size != sizeof(pubKey)) + { + return false; + } + + for (int i = 0; i < buf->size; ++i) + { + if (buf->buffer[i] != pubKey[i]) + { + return false; + } + } + + return true; +} diff --git a/src/utils/root_key_utils/tests/root_key_utils_ut.cpp b/src/utils/root_key_utils/tests/root_key_utils_ut.cpp new file mode 100644 index 000000000..a0603b96a --- /dev/null +++ b/src/utils/root_key_utils/tests/root_key_utils_ut.cpp @@ -0,0 +1,388 @@ +/** + * @file root_key_utils_ut.cpp + * @brief Unit Tests for root_key_utils library + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#include "base64_utils.h" +#include "crypto_lib.h" + +#define ENABLE_MOCKS +#include "root_key_list.h" +#include "root_key_store.h" +#undef ENABLE_MOCKS + +#include "aduc/rootkeypackage_parse.h" +#include "aduc/rootkeypackage_utils.h" +#include "root_key_util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ADUC::StringUtils::cstr_wrapper; +using Catch::Matchers::Equals; +using uint8_t_wrapper = ADUC::StringUtils::calloc_wrapper; + +const RSARootKey testHardcodedRootKeys[] = { + { "testrootkey1", + "rPMhXSpDY53R8pZJi0oW3qvP9l_9ntRkJo-2US109_wr5_P-t54uCx-EwZs7UkXYNYnyu8GIbzL2dyQp7lMhmLv_cQFIhs6HMlLpSIMtbHYq_v6jMgdGb5ovfbwPbMsiESQiZc0xSEVMq60p8iCw58gIzMK1nWdYeUQMC8mU-G-O8c_z8SXlVjbwZ5AmjVg42Z3NW558gcgez0LxkRnGyALHZCCjJNSUjPTp7AMKL21S-C6aFFVWwFJdeUrhJkf__2cdAB6m3C6-wuO2pq1HRX-epjMmnQ06UjdUmKuIUjB2uyVcMTnkVzXPUD6D2rbBFAy1230Svw20YSP8P7n9xQ", + 65537 }, + { "testrootkey2", + "tKN8mDrKOtLIsUjPC_KHcu6YcyitaG9nKtpR_WQAYT8rNjtlORd5H2TuAsr4DutkX7x6SZv3y5RyTqVZKZNkmlbUALoRR1bJ-pGkEUtntB9Oaga2ZcmtYYOwTy2QdOLEee_fE6UZun-mWNPv2swMhmWJuMTkixUakq8PN4bSPDNjdn_moVowXmfesN31Ioi97zxKSp9XXhU6E92MX2E782-uxqshPFe-xEWRLGCA50-_yJeJMiRJSiMZdjQ4Su9o6D86WdgiTERP9cUoSQFoZWFnG8c76WL_Gn0T6pM47kPOJeGv2ZyDm9hGrLL2bjI2WTevDmOrzCjf8qHw6Kg58Q", + 65537 } +}; + +static std::string get_valid_example_rootkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/root_key_utils/validrootkeypackage.json"; + return path; +}; + +static std::string get_invalid_example_rootkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/root_key_utils/invalidrootkeypackage.json"; + return path; +}; + +static std::string get_nonexistent_example_rootkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/root_key_utils/doesnotexistrootkeypackage.json"; + return path; +}; + +static std::string get_dest_rootkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/root_key_utils/test-rootkeypackage-write.json"; + return path; +}; + +static std::string get_prod_disabled_rootkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/root_key_utils/disabledRootKeyProd.json"; + return path; +}; + +static std::string get_prod_disabled_signingkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/root_key_utils/disabledSigningKeyProd.json"; + return path; +}; + +// Correct signature, +// clang-format off +std::string validRootKeyPackageJson = R"({"protected":{"version":1,"published":1675972876,"disabledRootKeys":[],"disabledSigningKeys":[],"rootKeys":{"testrootkey1":{"keyType":"RSA","n":"rPMhXSpDY53R8pZJi0oW3qvP9l_9ntRkJo-2US109_wr5_P-t54uCx-EwZs7UkXYNYnyu8GIbzL2dyQp7lMhmLv_cQFIhs6HMlLpSIMtbHYq_v6jMgdGb5ovfbwPbMsiESQiZc0xSEVMq60p8iCw58gIzMK1nWdYeUQMC8mU-G-O8c_z8SXlVjbwZ5AmjVg42Z3NW558gcgez0LxkRnGyALHZCCjJNSUjPTp7AMKL21S-C6aFFVWwFJdeUrhJkf__2cdAB6m3C6-wuO2pq1HRX-epjMmnQ06UjdUmKuIUjB2uyVcMTnkVzXPUD6D2rbBFAy1230Svw20YSP8P7n9xQ","e":65537},"testrootkey2":{"keyType":"RSA","n":"tKN8mDrKOtLIsUjPC_KHcu6YcyitaG9nKtpR_WQAYT8rNjtlORd5H2TuAsr4DutkX7x6SZv3y5RyTqVZKZNkmlbUALoRR1bJ-pGkEUtntB9Oaga2ZcmtYYOwTy2QdOLEee_fE6UZun-mWNPv2swMhmWJuMTkixUakq8PN4bSPDNjdn_moVowXmfesN31Ioi97zxKSp9XXhU6E92MX2E782-uxqshPFe-xEWRLGCA50-_yJeJMiRJSiMZdjQ4Su9o6D86WdgiTERP9cUoSQFoZWFnG8c76WL_Gn0T6pM47kPOJeGv2ZyDm9hGrLL2bjI2WTevDmOrzCjf8qHw6Kg58Q","e":65537}}},"signatures":[{"alg":"RS256","sig":"AjXYiFNj7kN7jbKZckwBQXDBiLKCTPQj8Oh1aqaUteW8tjyg6MZGjev-V8MirIw77e4xTLj7ZgBPt_qgWXH-otVal1zyUJlolPsmicugm8whhS4OVOqGfMJ8jTbT8yjiHGdKR3nWW1EQbRE6y38iAYCETXrHgVA2BM77fkBHj27P1etYPCkkjSdKtN6D-gdAuAzNsRQOv-8YZkIuMeD1d9kZAoHbDYmfpVHjooBd1_iys8f4aRKkhk18_3Alsxx63VtTNK3eSkPqb1v3Z-fpGnpW0rJZbf4XskCuTyysPu_Vgmnxn2CJccfseijlnnQiqpN5jEaNOU4TX_Yhc15wMg"},{"alg":"RS256","sig":"SBWi1Ae0EWrj9EKrL4qQGh_xumhdLl1BhASGX1Jc8QaM9PtreRIOIMxbC7LaZXmpTyjDrxpaNKwwIBVO8poWT5BocchL8vzcn0KTAwbl0OD-zoa5CdvurrtQJkx0L-yr685oz4AP05SiRBRuSYPGCty0D4Pzy09Yp9gHDN_2KGnFfkph5I64GmA6CB9mexXXz26xSucYHpMApO9yUgpkYCBVirdgP7aKyb-c6GK4LLuLCi_nTtrUMfEpfxYNmNp4zm0R2IjQ_C9Jyn7mY3YO3sSPRw88iv5f0QzKTGazRdkOHOnwPbDdsykZ4uSABBKtCKN9VVSUusnuv53ZPkc63Q"}]})"; +// clang-format on + +// clang-format off +std::string invalidRootKeyPackageJson = R"({"protected":{"version":1,"published":1675972876,"disabledRootKeys":[],"disabledSigningKeys":[],"rootKeys":{"testrootkey1":{"keyType":"RSA","n":"rPMhXSpDY53R8pZJi0oW3qvP9l_9ntRkJo-2US109_wr5_P-t54uCx-EwZs7UkXYNYnyu8GIbzL2dyQp7lMhmLv_cQFIhs6HMlLpSIMtbHYq_v6jMgdGb5ovfbwPbMsiESQiZc0xSEVMq60p8iCw58gIzMK1nWdYeUQMC8mU-G-O8c_z8SXlVjbwZ5AmjVg42Z3NW558gcgez0LxkRnGyALHZCCjJNSUjPTp7AMKL21S-C6aFFVWwFJdeUrhJkf__2cdAB6m3C6-wuO2pq1HRX-epjMmnQ06UjdUmKuIUjB2uyVcMTnkVzXPUD6D2rbBFAy1230Svw20YSP8P7n9xQ","e":65537},"testrootkey2":{"keyType":"RSA","n":"tKN8mDrKOtLIsUjPC_KHcu6YcyitaG9nKtpR_WQAYT8rNjtlORd5H2TuAsr4DutkX7x6SZv3y5RyTqVZKZNkmlbUALoRR1bJ-pGkEUtntB9Oaga2ZcmtYYOwTy2QdOLEee_fE6UZun-mWNPv2swMhmWJuMTkixUakq8PN4bSPDNjdn_moVowXmfesN31Ioi97zxKSp9XXhU6E92MX2E782-uxqshPFe-xEWRLGCA50-_yJeJMiRJSiMZdjQ4Su9o6D86WdgiTERP9cUoSQFoZWFnG8c76WL_Gn0T6pM47kPOJeGv2ZyDm9hGrLL2bjI2WTevDmOrzCjf8qHw6Kg58Q","e":65537}}},"signatures":[{"alg":"RS256","sig":"AjXYiFNj7kN7jbKZckwBQXDBiLKCTPQj8Oh1aqaUteW8tjyg6MZGjev-V8MirIw77e4xTLj7ZgBPt_qgWXH-otVal1zyUJlolPsmicugm8whhS4OVOqGfMJ8jTbT8yjiHGdKR3nWW1EQbRE6y38iAYCETXrHgVA2BM77fkBHj27P1etYPCkkjSdKtN6D-gdAuAzNsRQOv-8YZkIuMeD1d9kZAoHbDYmfpVHjooBd1_iys8f4aRKkhk18_3Alsxx63VtTNK3eSkPqb1v3Z-fpGnpW0rJZbf4XskCuTyysPu_Vgmnxn2CJccfseijlnnQiqpN5jEaNOU4TX_Yhc15wMg"},{"alg":"RS256","sig":"SBWi1Ae0EWrj9EKrL4qQGh_xumhdLl1BhASGX1Jc8QaM9PtreRIOIMxbC7LaZXmpTyjDrxpaNKwwIBVO8poWT5BocchL8vzcn0KTAwbl0OD-zoa5CdvurrtQJkx0L-yr685oz4AP05SiRBRuSYPGCty0D4Pzy09Yp9gHDN_2KGnFfkph5I64GmA6CB9mexXXz26xSucYHpMApO9yUgpkYCBVirdgP7aKyb-c6GK4LLuLCi_nTtrUMfEpfxYNmNp4zm0R2IjQ_C9Jyn7mY3YO3sSPRw88iv5f0QzKTGazRdkOHOnwPbDdsykZ4uSABBKtCKN9VVSUusnuv53ZPk1234"}]})"; +// // clang-format on + + + +const RSARootKey* MockRootKeyList_GetHardcodedRsaRootKeys() +{ + return testHardcodedRootKeys; +} + +size_t MockRootKeyList_numHardcodedKeys() +{ + return ARRAY_SIZE(testHardcodedRootKeys); +} + +std::string g_mockedRootKeyStorePath = ""; + +const char* MockRootKeyStore_GetRootKeyStorePath() +{ + return g_mockedRootKeyStorePath.c_str(); +} + +class SignatureValidationMockHook +{ +public: + SignatureValidationMockHook() + { + REGISTER_GLOBAL_MOCK_HOOK(RootKeyList_GetHardcodedRsaRootKeys, MockRootKeyList_GetHardcodedRsaRootKeys); + REGISTER_GLOBAL_MOCK_HOOK(RootKeyList_numHardcodedKeys, MockRootKeyList_numHardcodedKeys); + } + + ~SignatureValidationMockHook() = default; + + SignatureValidationMockHook(const SignatureValidationMockHook&) = delete; + SignatureValidationMockHook& operator=(const SignatureValidationMockHook&) = delete; + SignatureValidationMockHook(SignatureValidationMockHook&&) = delete; + SignatureValidationMockHook& operator=(SignatureValidationMockHook&&) = delete; +}; + +class GetRootKeyValidationMockHook +{ +public: + GetRootKeyValidationMockHook() + { + REGISTER_GLOBAL_MOCK_HOOK(RootKeyList_GetHardcodedRsaRootKeys, MockRootKeyList_GetHardcodedRsaRootKeys); + REGISTER_GLOBAL_MOCK_HOOK(RootKeyList_numHardcodedKeys, MockRootKeyList_numHardcodedKeys); + REGISTER_GLOBAL_MOCK_HOOK(RootKeyStore_GetRootKeyStorePath, MockRootKeyStore_GetRootKeyStorePath); + } + + ~GetRootKeyValidationMockHook() = default; + + GetRootKeyValidationMockHook(const SignatureValidationMockHook&) = delete; + GetRootKeyValidationMockHook& operator=(const SignatureValidationMockHook&) = delete; + GetRootKeyValidationMockHook(SignatureValidationMockHook&&) = delete; + GetRootKeyValidationMockHook& operator=(SignatureValidationMockHook&&) = delete; +}; + +TEST_CASE_METHOD(SignatureValidationMockHook, "RootKeyUtility_ValidateRootKeyPackage Signature Validation") +{ + SECTION("RootKeyUtility_ValidateRootKeyPackage - Valid RootKeyPackage Signature") + { + ADUC_RootKeyPackage pkg = {}; + + ADUC_Result result = ADUC_RootKeyPackageUtils_Parse(validRootKeyPackageJson.c_str(),&pkg); + + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + ADUC_Result validationResult = RootKeyUtility_ValidateRootKeyPackageWithHardcodedKeys(&pkg); + + CHECK(IsAducResultCodeSuccess(validationResult.ResultCode)); + + } + SECTION("RootKeyUtil_ValidateRootKeyPackage - Invalid RootKeyPackage Signature") + { + ADUC_RootKeyPackage pkg = {}; + + ADUC_Result result = ADUC_RootKeyPackageUtils_Parse(invalidRootKeyPackageJson.c_str(),&pkg); + + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + ADUC_Result validationResult = RootKeyUtility_ValidateRootKeyPackageWithHardcodedKeys(&pkg); + + CHECK(validationResult.ExtendedResultCode == ADUC_ERC_UTILITIES_ROOTKEYUTIL_SIGNATURE_VALIDATION_FAILED); + } +} + + +TEST_CASE_METHOD(SignatureValidationMockHook, "RootKeyUtility_LoadPackageFromDisk") +{ + SECTION("Success case- valid package with valid signatures") + { + std::string filePath = get_valid_example_rootkey_package_json_path(); + ADUC_RootKeyPackage* rootKeyPackage = nullptr; + + ADUC_Result result = RootKeyUtility_LoadPackageFromDisk(&rootKeyPackage,filePath.c_str(), true /* validateSignatures */); + + CHECK(IsAducResultCodeSuccess(result.ResultCode)); + CHECK(rootKeyPackage != nullptr); + + ADUC_RootKeyPackage correctPackage = {}; + + ADUC_Result lResult = ADUC_RootKeyPackageUtils_Parse(validRootKeyPackageJson.c_str(),&correctPackage); + + REQUIRE(IsAducResultCodeSuccess(lResult.ResultCode)); + + CHECK(ADUC_RootKeyPackageUtils_AreEqual(rootKeyPackage,&correctPackage)); + + ADUC_RootKeyPackageUtils_Destroy(rootKeyPackage); + free(rootKeyPackage); + } + SECTION ("Fail case - valid test package path, invalid signature") + { + std::string filePath = get_invalid_example_rootkey_package_json_path(); + ADUC_RootKeyPackage* rootKeyPackage = nullptr; + + ADUC_Result result = RootKeyUtility_LoadPackageFromDisk(&rootKeyPackage,filePath.c_str(), true /* validateSignatures */); + + CHECK(IsAducResultCodeFailure(result.ResultCode)); + REQUIRE(rootKeyPackage == nullptr); + } + SECTION ("Fail case - invalid test package path") + { + std::string filePath = get_nonexistent_example_rootkey_package_json_path(); + + ADUC_RootKeyPackage* rootKeyPackage = nullptr; + + ADUC_Result result = RootKeyUtility_LoadPackageFromDisk(&rootKeyPackage,filePath.c_str(), true /* validateSignatures */); + CHECK(IsAducResultCodeFailure(result.ResultCode)); + + CHECK(result.ExtendedResultCode == ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_CANT_LOAD_FROM_STORE); + + REQUIRE(rootKeyPackage == nullptr); + } +} + +TEST_CASE_METHOD(SignatureValidationMockHook,"RootKeyUtility_WriteRootKeyPackageToFileAtomically") +{ + SECTION("Success case") + { + std::string filePath = get_dest_rootkey_package_json_path(); + ADUC_RootKeyPackage loadedRootKeyPackage = {}; + ADUC_RootKeyPackage* writtenRootKeyPackage = nullptr; + + STRING_HANDLE destPath = STRING_construct(filePath.c_str()); + REQUIRE(destPath != nullptr); + + ADUC_Result pResult = ADUC_RootKeyPackageUtils_Parse(validRootKeyPackageJson.c_str(),&loadedRootKeyPackage); + + REQUIRE(IsAducResultCodeSuccess(pResult.ResultCode)); + + ADUC_Result wResult = RootKeyUtility_WriteRootKeyPackageToFileAtomically(&loadedRootKeyPackage,destPath); + + CHECK(IsAducResultCodeSuccess(wResult.ResultCode)); + + ADUC_Result lResult = RootKeyUtility_LoadPackageFromDisk(&writtenRootKeyPackage,filePath.c_str(), true /* validateSignatures */); + + REQUIRE(IsAducResultCodeSuccess(lResult.ResultCode)); + REQUIRE(writtenRootKeyPackage != nullptr); + + CHECK(ADUC_RootKeyPackageUtils_AreEqual(writtenRootKeyPackage,&loadedRootKeyPackage)); + + ADUC_RootKeyPackageUtils_Destroy(&loadedRootKeyPackage); + ADUC_RootKeyPackageUtils_Destroy(writtenRootKeyPackage); + + free(writtenRootKeyPackage); + + STRING_delete(destPath); + } +} + +TEST_CASE("RootKeyUtility_RootKeyIsDisabled") +{ + ADUC_RootKeyPackage* pkg = nullptr; + std::string filePath = get_prod_disabled_rootkey_package_json_path(); + ADUC_Result lResult = RootKeyUtility_LoadPackageFromDisk(&pkg, filePath.c_str(), false /* validateSignatures */); + REQUIRE(IsAducResultCodeSuccess(lResult.ResultCode)); + REQUIRE(pkg != nullptr); + CHECK(RootKeyUtility_RootKeyIsDisabled(pkg, "ADU.200702.R")); + CHECK_FALSE(RootKeyUtility_RootKeyIsDisabled(pkg, "ADU.200703.R")); + free(pkg); +} + +TEST_CASE("RootKeyUtility_ReloadPackageFromDisk") +{ + SECTION("bad signature should fail") + { + std::string filePath = get_prod_disabled_rootkey_package_json_path(); + ADUC_Result lResult = RootKeyUtility_ReloadPackageFromDisk(filePath.c_str(), true /* validateSignatures */); + CHECK(IsAducResultCodeFailure(lResult.ResultCode)); + } +} + +TEST_CASE("RootKeyUtility_GetDisabledSigningKeys") +{ + SECTION("prod - no disabled signing keys") + { + std::string filePath = get_prod_disabled_rootkey_package_json_path(); + ADUC_Result lResult = RootKeyUtility_ReloadPackageFromDisk(filePath.c_str(), false /* validateSignatures */); + REQUIRE(IsAducResultCodeSuccess(lResult.ResultCode)); + VECTOR_HANDLE disabledSigningKeyList = nullptr; + ADUC_Result result = RootKeyUtility_GetDisabledSigningKeys(&disabledSigningKeyList); + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + CHECK(disabledSigningKeyList != nullptr); + CHECK(VECTOR_size(disabledSigningKeyList) == 0); + } + + SECTION("prod - one disabled signing key") + { + std::string filePath = get_prod_disabled_signingkey_package_json_path(); + ADUC_Result lResult = RootKeyUtility_ReloadPackageFromDisk(filePath.c_str(), false /* validateSignatures */); + REQUIRE(IsAducResultCodeSuccess(lResult.ResultCode)); + VECTOR_HANDLE disabledSigningKeyList = nullptr; + ADUC_Result result = RootKeyUtility_GetDisabledSigningKeys(&disabledSigningKeyList); + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + CHECK(disabledSigningKeyList != nullptr); + CHECK(VECTOR_size(disabledSigningKeyList) == 1); + CHECK(VECTOR_element(disabledSigningKeyList, 0) != nullptr); + auto hashElement = (ADUC_RootKeyPackage_Hash*)VECTOR_element(disabledSigningKeyList, 0); + CHECK(hashElement->alg == SHA256); + CHECK(hashElement->hash != nullptr); + + cstr_wrapper base64url{ Base64URLEncode(CONSTBUFFER_GetContent(hashElement->hash)->buffer, CONSTBUFFER_GetContent(hashElement->hash)->size) }; + CHECK_THAT(base64url.get(), Equals("q5xF2ARjhdtH-kaLNTwZAMoXdy0iJQjziQ_AyZWDPRA")); + } +} + +TEST_CASE_METHOD(GetRootKeyValidationMockHook, "RootKeyUtility_GetKeyForKid") +{ + SECTION("Get hardcoded key") + { + // set the store path to the valid package tht we know contains the hardcoded key + g_mockedRootKeyStorePath = get_valid_example_rootkey_package_json_path(); + + // make sure to reload the store + RootKeyUtility_ReloadPackageFromDisk(g_mockedRootKeyStorePath.c_str(), true /* validateSignatures */); + CryptoKeyHandle key = nullptr; + const char* keyId = "testrootkey1"; + + ADUC_Result result = RootKeyUtility_GetKeyForKid(&key, keyId); + + CHECK(IsAducResultCodeSuccess(result.ResultCode)); + + CHECK(key != nullptr); + + CryptoUtils_FreeCryptoKeyHandle(key); + } + SECTION("Get hardcoded key, disabled") + { + // set the store path to the valid package tht we know contains the hardcoded key + g_mockedRootKeyStorePath = get_prod_disabled_rootkey_package_json_path(); + + // Make sure to reload the store + RootKeyUtility_ReloadPackageFromDisk(g_mockedRootKeyStorePath.c_str(), true /* validateSignatures */); + + CryptoKeyHandle key = nullptr; + const char* keyId = "ADU.200702.R"; + + ADUC_Result result = RootKeyUtility_GetKeyForKid(&key, keyId); + + CHECK(IsAducResultCodeFailure(result.ResultCode)); + + CHECK(key == nullptr); + + + } + SECTION("Get key from store") + { + // set the store path to the valid package tht we know contains the hardcoded key + g_mockedRootKeyStorePath = get_valid_example_rootkey_package_json_path(); + + // make sure to reload the store + RootKeyUtility_ReloadPackageFromDisk(g_mockedRootKeyStorePath.c_str(), true /* validateSignatures */); + CryptoKeyHandle key = nullptr; + const char* keyId = "testrootkey1"; + + ADUC_Result result = RootKeyUtility_GetKeyForKid(&key, keyId); + + CHECK(IsAducResultCodeSuccess(result.ResultCode)); + + CHECK(key != nullptr); + + CryptoUtils_FreeCryptoKeyHandle(key); + } + SECTION("Get non-existent key") + { + // set the store path to the valid package tht we know contains the hardcoded key + g_mockedRootKeyStorePath = get_nonexistent_example_rootkey_package_json_path(); + + // make sure to reload the store + RootKeyUtility_ReloadPackageFromDisk(g_mockedRootKeyStorePath.c_str(), true /* validateSignatures */); + CryptoKeyHandle key = nullptr; + const char* keyId = "testrootkey3"; + + ADUC_Result result = RootKeyUtility_GetKeyForKid(&key, keyId); + + CHECK(IsAducResultCodeFailure(result.ResultCode)); + + CHECK(key == nullptr); + } +} diff --git a/src/utils/root_key_utils/tests/testdata/root_key_utils/disabledRootKeyProd.json b/src/utils/root_key_utils/tests/testdata/root_key_utils/disabledRootKeyProd.json new file mode 100644 index 000000000..7a197b358 --- /dev/null +++ b/src/utils/root_key_utils/tests/testdata/root_key_utils/disabledRootKeyProd.json @@ -0,0 +1,30 @@ +{ + "protected": + { + "version": 1, + "published": 1694725889, + "disabledRootKeys": [ + "ADU.200702.R" + ], + "disabledSigningKeys": [], + "rootKeys": { + "ADU.200702.R": { + "keyType": "RSA", + "n": "1UIurxFUo1Blh6JNW7oa-6ky3-mZXwVFyK-9NR2J6CcnWKOo7sXFHk_3kqYSBn09fbAH9ix_3m0q9bxJvBXv8IHLP4hPJx2IcShgCLYZ0tI50AUfPHaGcbtZWLyxiHurVii_MXNEMhD9PdOWXP9OXLNr_4uEm4uAuEnQffrWQFh2TcByJ3XLmi-btJ8PJfEcxRsLWjB9L7jvpyZYU6_VHVUBUQ3pG6IPP9fpHSBBpuYUCq7-8hwq1uQEe_YUfuwPl4P6WPqBNiG5oyv62WELGpT3wb5_QBRKyfo1f-9mcACx_dvXYQ07WHRnlIl1dpZ8kYfSjhGX7nuHbJovRdhlP1JwmCrLyARj9clHz3D07WSndKUjj7bt9xzTsBxkVxJaqYGEH6DnUBmWtIKxrEjj4TKCy0AfrMRZvBA0UYL5KI2oHpv1eUV1styaEUMIvmHMmsTLdzb_g92ocU9Rjg57Tfp5mI2-_IJ-QEipEgGo2X7zpRvx-5B3PkCHGMmr2fd5", + "e": 65537 + }, + "ADU.200703.R": { + "keyType": "RSA", + "n": "sqOydBb6uyD5UnbmJz6AQcb-zzD5yJb1WQqqgedRg4rE9Rc6LyrmV9Rxzoo975pVdj6Z4sKuTO4tuHj1ok4o8pxOOWW87OQN5eM4qFmrCKQbtPSgUqM4s0YhE8w8aAbe_gCmkm7eTEcQ1hycJPXNcOH1anxoEx3hxfaoTyGfhnxExYqZHMXTBptacZ0JHMNkMWrFF5UdXSrxVcdm1Oj12albjKJsYmAFN9cysHPL90s2JyQhjDgKuBj-9RVgNYs17x4PiKYTjXt977PnsMmmHHB7zPIpi4f3vZ22iG-sc_9y8u9IJ5ZyhgaiXON9zrCe5cLZTsTzf3gHS2WIRQwR5ZZWNIgtFg5ZQtL32e0d7ck3d0R-44Q2n1gT72_kw0TUdwaKz1vIgByimGULNdxzyGnQXuglQ5722KsFr1EpI1VAWBDquOLNXXnM7N-0W5jH-uPSbCbOLixW4M-N7v2TEi8ASY0cgjhWpl15REoa89wWELPBLScR_huYBeSjYDGZ", + "e": 65537 + } + } + }, + "signatures": + [ + { + "alg": "RS256", + "sig": "ToDo" + } + ] +} diff --git a/src/utils/root_key_utils/tests/testdata/root_key_utils/disabledSigningKeyProd.json b/src/utils/root_key_utils/tests/testdata/root_key_utils/disabledSigningKeyProd.json new file mode 100644 index 000000000..ea437936d --- /dev/null +++ b/src/utils/root_key_utils/tests/testdata/root_key_utils/disabledSigningKeyProd.json @@ -0,0 +1,33 @@ +{ + "protected": + { + "version": 1, + "published": 1694725889, + "disabledRootKeys": [], + "disabledSigningKeys": [ + { + "alg": "SHA256", + "hash": "q5xF2ARjhdtH-kaLNTwZAMoXdy0iJQjziQ_AyZWDPRA" + } + ], + "rootKeys": { + "ADU.200702.R": { + "keyType": "RSA", + "n": "1UIurxFUo1Blh6JNW7oa-6ky3-mZXwVFyK-9NR2J6CcnWKOo7sXFHk_3kqYSBn09fbAH9ix_3m0q9bxJvBXv8IHLP4hPJx2IcShgCLYZ0tI50AUfPHaGcbtZWLyxiHurVii_MXNEMhD9PdOWXP9OXLNr_4uEm4uAuEnQffrWQFh2TcByJ3XLmi-btJ8PJfEcxRsLWjB9L7jvpyZYU6_VHVUBUQ3pG6IPP9fpHSBBpuYUCq7-8hwq1uQEe_YUfuwPl4P6WPqBNiG5oyv62WELGpT3wb5_QBRKyfo1f-9mcACx_dvXYQ07WHRnlIl1dpZ8kYfSjhGX7nuHbJovRdhlP1JwmCrLyARj9clHz3D07WSndKUjj7bt9xzTsBxkVxJaqYGEH6DnUBmWtIKxrEjj4TKCy0AfrMRZvBA0UYL5KI2oHpv1eUV1styaEUMIvmHMmsTLdzb_g92ocU9Rjg57Tfp5mI2-_IJ-QEipEgGo2X7zpRvx-5B3PkCHGMmr2fd5", + "e": 65537 + }, + "ADU.200703.R": { + "keyType": "RSA", + "n": "sqOydBb6uyD5UnbmJz6AQcb-zzD5yJb1WQqqgedRg4rE9Rc6LyrmV9Rxzoo975pVdj6Z4sKuTO4tuHj1ok4o8pxOOWW87OQN5eM4qFmrCKQbtPSgUqM4s0YhE8w8aAbe_gCmkm7eTEcQ1hycJPXNcOH1anxoEx3hxfaoTyGfhnxExYqZHMXTBptacZ0JHMNkMWrFF5UdXSrxVcdm1Oj12albjKJsYmAFN9cysHPL90s2JyQhjDgKuBj-9RVgNYs17x4PiKYTjXt977PnsMmmHHB7zPIpi4f3vZ22iG-sc_9y8u9IJ5ZyhgaiXON9zrCe5cLZTsTzf3gHS2WIRQwR5ZZWNIgtFg5ZQtL32e0d7ck3d0R-44Q2n1gT72_kw0TUdwaKz1vIgByimGULNdxzyGnQXuglQ5722KsFr1EpI1VAWBDquOLNXXnM7N-0W5jH-uPSbCbOLixW4M-N7v2TEi8ASY0cgjhWpl15REoa89wWELPBLScR_huYBeSjYDGZ", + "e": 65537 + } + } + }, + "signatures": + [ + { + "alg": "RS256", + "sig": "ToDo" + } + ] +} diff --git a/src/utils/root_key_utils/tests/testdata/root_key_utils/invalidrootkeypackage.json b/src/utils/root_key_utils/tests/testdata/root_key_utils/invalidrootkeypackage.json new file mode 100644 index 000000000..c4a225235 --- /dev/null +++ b/src/utils/root_key_utils/tests/testdata/root_key_utils/invalidrootkeypackage.json @@ -0,0 +1,30 @@ +{ + "protected": { + "version": 1, + "published": 1675972876, + "disabledRootKeys": [], + "disabledSigningKeys": [], + "rootKeys": { + "testrootkey1": { + "keyType": "RSA", + "n": "rPMhXSpDY53R8pZJi0oW3qvP9l_9ntRkJo-2US109_wr5_P-t54uCx-EwZs7UkXYNYnyu8GIbzL2dyQp7lMhmLv_cQFIhs6HMlLpSIMtbHYq_v6jMgdGb5ovfbwPbMsiESQiZc0xSEVMq60p8iCw58gIzMK1nWdYeUQMC8mU-G-O8c_z8SXlVjbwZ5AmjVg42Z3NW558gcgez0LxkRnGyALHZCCjJNSUjPTp7AMKL21S-C6aFFVWwFJdeUrhJkf__2cdAB6m3C6-wuO2pq1HRX-epjMmnQ06UjdUmKuIUjB2uyVcMTnkVzXPUD6D2rbBFAy1230Svw20YSP8P7n9xQ", + "e": 65537 + }, + "testrootkey2": { + "keyType": "RSA", + "n": "tKN8mDrKOtLIsUjPC_KHcu6YcyitaG9nKtpR_WQAYT8rNjtlORd5H2TuAsr4DutkX7x6SZv3y5RyTqVZKZNkmlbUALoRR1bJ-pGkEUtntB9Oaga2ZcmtYYOwTy2QdOLEee_fE6UZun-mWNPv2swMhmWJuMTkixUakq8PN4bSPDNjdn_moVowXmfesN31Ioi97zxKSp9XXhU6E92MX2E782-uxqshPFe-xEWRLGCA50-_yJeJMiRJSiMZdjQ4Su9o6D86WdgiTERP9cUoSQFoZWFnG8c76WL_Gn0T6pM47kPOJeGv2ZyDm9hGrLL2bjI2WTevDmOrzCjf8qHw6Kg58Q", + "e": 65537 + } + } + }, + "signatures": [ + { + "alg": "RS256", + "sig": "1234iFNj7kN7jbKZckwBQXDBiLKCTPQj8Oh1aqaUteW8tjyg6MZGjev-V8MirIw77e4xTLj7ZgBPt_qgWXH-otVal1zyUJlolPsmicugm8whhS4OVOqGfMJ8jTbT8yjiHGdKR3nWW1EQbRE6y38iAYCETXrHgVA2BM77fkBHj27P1etYPCkkjSdKtN6D-gdAuAzNsRQOv-8YZkIuMeD1d9kZAoHbDYmfpVHjooBd1_iys8f4aRKkhk18_3Alsxx63VtTNK3eSkPqb1v3Z-fpGnpW0rJZbf4XskCuTyysPu_Vgmnxn2CJccfseijlnnQiqpN5jEaNOU4TX_Yhc15wMg" + }, + { + "alg": "RS256", + "sig": "123i1Ae0EWrj9EKrL4qQGh_xumhdLl1BhASGX1Jc8QaM9PtreRIOIMxbC7LaZXmpTyjDrxpaNKwwIBVO8poWT5BocchL8vzcn0KTAwbl0OD-zoa5CdvurrtQJkx0L-yr685oz4AP05SiRBRuSYPGCty0D4Pzy09Yp9gHDN_2KGnFfkph5I64GmA6CB9mexXXz26xSucYHpMApO9yUgpkYCBVirdgP7aKyb-c6GK4LLuLCi_nTtrUMfEpfxYNmNp4zm0R2IjQ_C9Jyn7mY3YO3sSPRw88iv5f0QzKTGazRdkOHOnwPbDdsykZ4uSABBKtCKN9VVSUusnuv53ZPkc63Q" + } + ] +} diff --git a/src/utils/root_key_utils/tests/testdata/root_key_utils/validrootkeypackage.json b/src/utils/root_key_utils/tests/testdata/root_key_utils/validrootkeypackage.json new file mode 100644 index 000000000..d64bcfc8d --- /dev/null +++ b/src/utils/root_key_utils/tests/testdata/root_key_utils/validrootkeypackage.json @@ -0,0 +1,30 @@ +{ + "protected": { + "version": 1, + "published": 1675972876, + "disabledRootKeys": [], + "disabledSigningKeys": [], + "rootKeys": { + "testrootkey1": { + "keyType": "RSA", + "n": "rPMhXSpDY53R8pZJi0oW3qvP9l_9ntRkJo-2US109_wr5_P-t54uCx-EwZs7UkXYNYnyu8GIbzL2dyQp7lMhmLv_cQFIhs6HMlLpSIMtbHYq_v6jMgdGb5ovfbwPbMsiESQiZc0xSEVMq60p8iCw58gIzMK1nWdYeUQMC8mU-G-O8c_z8SXlVjbwZ5AmjVg42Z3NW558gcgez0LxkRnGyALHZCCjJNSUjPTp7AMKL21S-C6aFFVWwFJdeUrhJkf__2cdAB6m3C6-wuO2pq1HRX-epjMmnQ06UjdUmKuIUjB2uyVcMTnkVzXPUD6D2rbBFAy1230Svw20YSP8P7n9xQ", + "e": 65537 + }, + "testrootkey2": { + "keyType": "RSA", + "n": "tKN8mDrKOtLIsUjPC_KHcu6YcyitaG9nKtpR_WQAYT8rNjtlORd5H2TuAsr4DutkX7x6SZv3y5RyTqVZKZNkmlbUALoRR1bJ-pGkEUtntB9Oaga2ZcmtYYOwTy2QdOLEee_fE6UZun-mWNPv2swMhmWJuMTkixUakq8PN4bSPDNjdn_moVowXmfesN31Ioi97zxKSp9XXhU6E92MX2E782-uxqshPFe-xEWRLGCA50-_yJeJMiRJSiMZdjQ4Su9o6D86WdgiTERP9cUoSQFoZWFnG8c76WL_Gn0T6pM47kPOJeGv2ZyDm9hGrLL2bjI2WTevDmOrzCjf8qHw6Kg58Q", + "e": 65537 + } + } + }, + "signatures": [ + { + "alg": "RS256", + "sig": "AjXYiFNj7kN7jbKZckwBQXDBiLKCTPQj8Oh1aqaUteW8tjyg6MZGjev-V8MirIw77e4xTLj7ZgBPt_qgWXH-otVal1zyUJlolPsmicugm8whhS4OVOqGfMJ8jTbT8yjiHGdKR3nWW1EQbRE6y38iAYCETXrHgVA2BM77fkBHj27P1etYPCkkjSdKtN6D-gdAuAzNsRQOv-8YZkIuMeD1d9kZAoHbDYmfpVHjooBd1_iys8f4aRKkhk18_3Alsxx63VtTNK3eSkPqb1v3Z-fpGnpW0rJZbf4XskCuTyysPu_Vgmnxn2CJccfseijlnnQiqpN5jEaNOU4TX_Yhc15wMg" + }, + { + "alg": "RS256", + "sig": "SBWi1Ae0EWrj9EKrL4qQGh_xumhdLl1BhASGX1Jc8QaM9PtreRIOIMxbC7LaZXmpTyjDrxpaNKwwIBVO8poWT5BocchL8vzcn0KTAwbl0OD-zoa5CdvurrtQJkx0L-yr685oz4AP05SiRBRuSYPGCty0D4Pzy09Yp9gHDN_2KGnFfkph5I64GmA6CB9mexXXz26xSucYHpMApO9yUgpkYCBVirdgP7aKyb-c6GK4LLuLCi_nTtrUMfEpfxYNmNp4zm0R2IjQ_C9Jyn7mY3YO3sSPRw88iv5f0QzKTGazRdkOHOnwPbDdsykZ4uSABBKtCKN9VVSUusnuv53ZPkc63Q" + } + ] +} diff --git a/src/utils/rootkeypackage_utils/CMakeLists.txt b/src/utils/rootkeypackage_utils/CMakeLists.txt new file mode 100644 index 000000000..1b57dc762 --- /dev/null +++ b/src/utils/rootkeypackage_utils/CMakeLists.txt @@ -0,0 +1,34 @@ +set (target_name rootkeypackage_utils) + +include (agentRules) +compileasc99 () +disablertti () + +find_package (Parson REQUIRED) + +add_library (${target_name} STATIC) +add_library (aduc::${target_name} ALIAS ${target_name}) + + +set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON) + +target_sources ( + ${target_name} PRIVATE src/rootkeypackage_download.c src/rootkeypackage_parse.c + src/rootkeypackage_utils.c src/rootkeypackage_do_download.cpp) + +target_include_directories (${target_name} PUBLIC inc ${ADUC_EXPORT_INCLUDES}) + +target_link_aziotsharedutil (${target_name} PUBLIC) +target_link_dosdk (${target_name} PRIVATE) + +target_link_libraries ( + ${target_name} + PUBLIC aduc::c_utils aduc::hash_utils libaducpal + PRIVATE aduc::crypto_utils aduc::logging aduc::system_utils aduc::url_utils Parson::parson) + +target_compile_definitions ( + ${target_name} PRIVATE ADUC_ROOTKEY_PKG_URL_OVERRIDE="${ADUC_ROOTKEY_PKG_URL_OVERRIDE}") + +if (ADUC_BUILD_UNIT_TESTS) + add_subdirectory (tests) +endif () diff --git a/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage.schema.json b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage.schema.json new file mode 100644 index 000000000..069ba6c13 --- /dev/null +++ b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage.schema.json @@ -0,0 +1,111 @@ +{ + "$id": "https://json.schemastore.org/azure-deviceupdate-rootkeypackage-1.0.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "protected": { + "type": "object", + "properties": { + "isTest": { + "type": "boolean" + }, + "version": { + "type": "number" + }, + "published": { + "type": "number" + }, + "disabledRootKeys": { + "type": "array", + "items": { + "type": "string" + } + }, + "disabledSigningKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/signingKeyHashDef" + } + }, + "rootKeys": { + "type": "object", + "patternProperties": { + ".*": { + "$ref": "#/definitions/rootKeyDef" + } + } + } + } + }, + "signatures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "alg": { + "enum": [ + "RS256", "RS384", "RS512" + ] + }, + "sig": { + "type": "string" + } + }, + "uniqueItems": true + } + } + }, + "required": [ + "protected", + "signatures" + ], + "definitions": { + "signingKeyHashDef": { + "type": "object", + "properties": { + "alg": { + "enum": [ + "SHA256", + "SHA384", + "SHA512" + ] + }, + "hash": { "type": "string" } + } + }, + "rootKeyDef": { + "type": "object", + "properties": { + "keyType": { + "enum": [ + "RSA" + ] + } + }, + "required": [ "keyType"], + "unevaluatedProperties": true, + "if": { + "type": "object", + "properties": { + "keyType": { + "const": "RSA" + } + } + }, + "then": { + "properties": { + "n": { + "type": "string" + }, + "e": { + "type": "string" + } + }, + "required": [ + "n", + "e" + ] + } + } + } +} diff --git a/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_do_download.h b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_do_download.h new file mode 100644 index 000000000..39087ace8 --- /dev/null +++ b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_do_download.h @@ -0,0 +1,22 @@ + +/** + * @file rootkeypackage_do_download.h + * @brief The root key package delivery optimization download header. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#ifndef ROOTKEYPACKAGE_DO_DOWNLOAD_H +#define ROOTKEYPACKAGE_DO_DOWNLOAD_H + +#include +#include + +EXTERN_C_BEGIN + +ADUC_Result DownloadRootKeyPkg_DO(const char* url, const char* targetFilePath); + +EXTERN_C_END + +#endif // ROOTKEYPACKAGE_DO_DOWNLOAD_H diff --git a/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_download.h b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_download.h new file mode 100644 index 000000000..33bb575dc --- /dev/null +++ b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_download.h @@ -0,0 +1,29 @@ + +/** + * @file rootkeypackage_download.h + * @brief The root key package download header. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#ifndef ROOTKEYPACKAGE_DOWNLOAD_H +#define ROOTKEYPACKAGE_DOWNLOAD_H + +#include + +typedef ADUC_Result (*RootKeyPkgDownloadFunc)(const char* rootKeyPkgUrl, const char* targetFilePath); + +/** + * @brief Root key package downloader info. + * + */ +typedef struct tagADUC_RootKeyPkgDownloaderInfo +{ + const char* name; /**< The name of the package downloader. */ + RootKeyPkgDownloadFunc downloadFn; /**< The downloader function. */ + const char* + downloadBaseDir; /**< The base directory under which to create a download sandbox dir for the file download. */ +} ADUC_RootKeyPkgDownloaderInfo; + +#endif // ROOTKEYPACKAGE_DOWNLOAD_H diff --git a/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_json_properties.h b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_json_properties.h new file mode 100644 index 000000000..4e03b6947 --- /dev/null +++ b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_json_properties.h @@ -0,0 +1,27 @@ + +/** + * @file rootkeypackage_json_properties.h + * @brief The root key package json property name and value definitions. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_PROTECTED "protected" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_ISTEST "isTest" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_VERSION "version" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_PUBLISHED "published" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_DISABLED_ROOT_KEYS "disabledRootKeys" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_DISABLED_SIGNING_KEYS "disabledSigningKeys" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_HASH "hash" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_KEY_TYPE "keyType" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_KEY_TYPE_RSA "RSA" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_RSA_MODULUS "n" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_RSA_EXPONENT "e" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_ROOTKEYS "rootKeys" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURES "signatures" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_ALG "alg" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_SIG "sig" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURE_ALG_RS256 "RS256" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURE_ALG_RS384 "RS384" +#define ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURE_ALG_RS512 "RS512" diff --git a/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_parse.h b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_parse.h new file mode 100644 index 000000000..9afcde459 --- /dev/null +++ b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_parse.h @@ -0,0 +1,41 @@ +/** + * @file rootkeypackage_parse.h + * @brief Header for rootkeypackage parse module. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#ifndef ROOTKEYPACKAGE_PARSE_H +#define ROOTKEYPACKAGE_PARSE_H + +#include "aduc/rootkeypackage_types.h" +#include +#include +#include +#include + +EXTERN_C_BEGIN + +ADUC_Result RootKeyPackage_ParseIsTest(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result RootKeyPackage_ParseVersion(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result RootKeyPackage_ParsePublished(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result RootKeyPackage_ParseDisabledRootKeys(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result RootKeyPackage_ParseHashAlg(JSON_Object* jsonObj, SHAversion* outAlg); +ADUC_Result RootKeyPackage_ParseSigningAlg(JSON_Object* jsonObj, ADUC_RootKeySigningAlgorithm* outAlg); +ADUC_Result +RootKeyPackage_ParseDisabledSigningKeys(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result RootKeyPackage_ParseRootKeys(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result +RootKeyPackage_ParseProtectedProperties(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result RootKeyPackage_ParseProtectedPropertiesString(JSON_Object* rootObj, ADUC_RootKeyPackage* outPackage); +ADUC_Result RootKeyPackage_ParseSignatures(JSON_Object* signaturesObj, ADUC_RootKeyPackage* outPackage); + +_Bool ADUC_RootKeyPackageUtils_AreEqual(const ADUC_RootKeyPackage* lPack, const ADUC_RootKeyPackage* rPack); +void ADUC_RootKey_DeInit(ADUC_RootKey* node); +void ADUC_RootKeyPackage_Hash_DeInit(ADUC_RootKeyPackage_Hash* node); +void ADUC_RootKeyPackage_Signature_DeInit(ADUC_RootKeyPackage_Signature* node); + +EXTERN_C_END + +#endif // ROOTKEYPACKAGE_PARSE_H diff --git a/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_types.h b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_types.h new file mode 100644 index 000000000..d43af7ac6 --- /dev/null +++ b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_types.h @@ -0,0 +1,100 @@ +/** + * @file rootkeypackage_types.h + * @brief rootkeypackage types. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#ifndef ROOTKEYPACKAGE_TYPES_H +#define ROOTKEYPACKAGE_TYPES_H + +#include +#include // for struct timespec +#include +#include +#include + +/** + * @brief The root key keyType. + */ +typedef enum tagADUC_RootKey_KeyType +{ + ADUC_RootKey_KeyType_INVALID = 0, + ADUC_RootKey_KeyType_RSA, /**< RSA keyType. */ +} ADUC_RootKey_KeyType; + +/** + * @brief The root key Signature algorithms. + */ +typedef enum tagADUC_RootKeySigningAlgorithm +{ + ADUC_RootKeySigningAlgorithm_INVALID = 0, + ADUC_RootKeySigningAlgorithm_RS256, /**< The RS256 algorithm. */ + ADUC_RootKeySigningAlgorithm_RS384, /**< The RS384 algorithm. */ + ADUC_RootKeySigningAlgorithm_RS512, /**< The RS512 algorithm. */ +} ADUC_RootKeySigningAlgorithm; + +/** + * @brief The Root key package hash. + */ +typedef struct tagADUC_RootKeyPackage_Hash +{ + SHAversion alg; /**< The hash algorithm. */ + CONSTBUFFER_HANDLE hash; /**< The hash const buffer handle. */ +} ADUC_RootKeyPackage_Hash; + +/** + * @brief The Root key package signature. + */ +typedef struct tagADUC_RootKeyPackage_Signature +{ + ADUC_RootKeySigningAlgorithm alg; /**< The signing algorithm. */ + CONSTBUFFER_HANDLE signature; /**< The signature const buffer handle. */ +} ADUC_RootKeyPackage_Signature; + +/** + * @brief The RSA root key parameters. + */ +typedef struct tagADUC_RSA_RootKeyParameters +{ + CONSTBUFFER_HANDLE n; /**< The RSA modulus parameter. */ + unsigned int e; /**< The RSA exponent parameter. */ +} ADUC_RSA_RootKeyParameters; + +/** + * @brief The root key. + */ +typedef struct tagADUC_RootKey +{ + STRING_HANDLE kid; /**< The key id. */ + ADUC_RootKey_KeyType keyType; /**< The key type. */ + ADUC_RSA_RootKeyParameters rsaParameters; /**< The RSA key parameters */ +} ADUC_RootKey; + +/** + * @brief The protected properties of the root key package. + */ +typedef struct tagADUC_RootKeyPackage_ProtectedProperties +{ + bool isTest; /**< Whether the rootkey package is a test package. */ + unsigned long version; /**< The monotonic increasing version of the package. */ + time_t publishedTime; /**< The unix time of the root key. */ + VECTOR_HANDLE disabledRootKeys; /**< handle to vector of STRING_HANDLE KIDS(KeyIds) of disabled root keys. */ + VECTOR_HANDLE + disabledSigningKeys; /**< handle to vector of ADUC_RootKeyPackage_Hash hashes of public key of disabled signing keys. */ + VECTOR_HANDLE rootKeys; /**< handle to vector of ADUC_RootKey root keys. */ +} ADUC_RootKeyPackage_ProtectedProperties; + +/** + * @brief The root key package. + */ +typedef struct tagADUC_RootKeyPackage +{ + ADUC_RootKeyPackage_ProtectedProperties protectedProperties; /**< The parsed protected properties. */ + STRING_HANDLE protectedPropertiesJsonString; /**< The serialized json string for which to verify the signatures. */ + VECTOR_HANDLE + signatures; /**< handle to vector of ADUC_RootKeyPackage_Signature signatures used to verify the protectedProperties using the provenance public root keys. */ +} ADUC_RootKeyPackage; + +#endif //ROOTKEYPACKAGE_TYPES_H diff --git a/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_utils.h b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_utils.h new file mode 100644 index 000000000..5f958e9cb --- /dev/null +++ b/src/utils/rootkeypackage_utils/inc/aduc/rootkeypackage_utils.h @@ -0,0 +1,38 @@ +/** + * @file rootkeypackage_utils.h + * @brief rootkeypackage_utils interface. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#ifndef ROOTKEYPACKAGE_UTILS_H +#define ROOTKEYPACKAGE_UTILS_H + +#include "aduc/rootkeypackage_download.h" +#include "aduc/rootkeypackage_types.h" +#include +#include +#include + +EXTERN_C_BEGIN + +ADUC_Result ADUC_RootKeyPackageUtils_DownloadPackage( + const char* rootKeyPkgUrl, + const char* workflowId, + ADUC_RootKeyPkgDownloaderInfo* downloaderInfo, + STRING_HANDLE* outRootKeyPackageDownloadedFile); + +ADUC_Result ADUC_RootKeyPackageUtils_Parse(const char* jsonString, ADUC_RootKeyPackage* outRootKeyPackage); + +char* ADUC_RootKeyPackageUtils_SerializePackageToJsonString(const ADUC_RootKeyPackage* rootKeyPackage); + +void ADUC_RootKeyPackageUtils_DisabledRootKeys_Destroy(ADUC_RootKeyPackage* rootKeyPackage); +void ADUC_RootKeyPackageUtils_DisabledSigningKeys_Destroy(ADUC_RootKeyPackage* rootKeyPackage); +void ADUC_RootKeyPackageUtils_RootKeys_Destroy(ADUC_RootKeyPackage* rootKeyPackage); +void ADUC_RootKeyPackageUtils_Signatures_Destroy(ADUC_RootKeyPackage* rootKeyPackage); +void ADUC_RootKeyPackageUtils_Destroy(ADUC_RootKeyPackage* rootKeyPackage); + +EXTERN_C_END + +#endif // ROOTKEYPACKAGE_UTILS_H diff --git a/src/utils/rootkeypackage_utils/src/rootkeypackage_do_download.cpp b/src/utils/rootkeypackage_utils/src/rootkeypackage_do_download.cpp new file mode 100644 index 000000000..348c3ee11 --- /dev/null +++ b/src/utils/rootkeypackage_utils/src/rootkeypackage_do_download.cpp @@ -0,0 +1,53 @@ +/** + * @file rootkeypackage_do_download.cpp + * @brief Implements delivery optimization download. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include +#include +#include +#include + +EXTERN_C_BEGIN + +ADUC_Result DownloadRootKeyPkg_DO(const char* url, const char* targetFilePath) +{ + ADUC_Result result = { ADUC_GeneralResult_Failure, 0 }; + + Log_Info("Downloading File '%s' to '%s'", url, targetFilePath); + + try + { + const std::error_code ret = microsoft::deliveryoptimization::download::download_url_to_path(url, targetFilePath); + if (ret.value() == 0) + { + result.ResultCode = ADUC_GeneralResult_Success; + } + else + { + // Note: The call to download_url_to_path() does not make use of a cancellation token, + // so the download can only timeout or hit a fatal error. + Log_Error( + "DO error, msg: %s, code: %#08x, timeout? %d", + ret.message().c_str(), + ret.value(), + ret == std::errc::timed_out); + + result.ExtendedResultCode = MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_INFRA_MGMT( + ADUC_COMPONENT_ROOTKEY_DOWNLOADER, ret.value()); + } + } + catch (...) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYUTIL_ROOTKEYPACKAGE_DOWNLOAD_EXCEPTION; + } + + Log_Info("Download rc: %d, erc: 0x%08x", result.ResultCode, result.ExtendedResultCode); + + return result; +} + +EXTERN_C_END diff --git a/src/utils/rootkeypackage_utils/src/rootkeypackage_download.c b/src/utils/rootkeypackage_utils/src/rootkeypackage_download.c new file mode 100644 index 000000000..d12bc4abf --- /dev/null +++ b/src/utils/rootkeypackage_utils/src/rootkeypackage_download.c @@ -0,0 +1,134 @@ +/** + * @file rootkeypackage_download.c + * @brief Implements ADUC_RootKeyPackageUtils_DownloadPackage of rootkeypackage_utils interface. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "aduc/rootkeypackage_download.h" +#include "aduc/rootkeypackage_do_download.h" +#include "aduc/rootkeypackage_utils.h" +#include +#include +#include +#include +#include // unlink + +EXTERN_C_BEGIN + +/** + * @brief Forces a download of the given URL to the rootkey pkg. + * + * @param rootKeyPkgUrl The URL of the root key package. + * @param workflowId The workflow Id for the associated deployment. + * @param downloaderInfo The downloader info used to download the rootkey package. + * @param[out] outRootKeyPackageDownloadedFile The resultant path to the root key package file. + * + * @result ADUC_Result On success, the outPathToRootKey with contain the path to the downloaded file. + */ +ADUC_Result ADUC_RootKeyPackageUtils_DownloadPackage( + const char* rootKeyPkgUrl, + const char* workflowId, + ADUC_RootKeyPkgDownloaderInfo* downloaderInfo, + STRING_HANDLE* outRootKeyPackageDownloadedFile) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + int err = 0; + + STRING_HANDLE targetDir = NULL; + STRING_HANDLE targetFileName = NULL; + STRING_HANDLE targetFilePath = NULL; + STRING_HANDLE targetUrl = NULL; + + if (IsNullOrEmpty(rootKeyPkgUrl) || IsNullOrEmpty(workflowId) || downloaderInfo == NULL + || IsNullOrEmpty(downloaderInfo->name) || IsNullOrEmpty(downloaderInfo->downloadBaseDir) + || downloaderInfo->downloadFn == NULL || outRootKeyPackageDownloadedFile == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_BADARG; + goto done; + } + + if ((targetDir = STRING_construct_sprintf("%s/%s", downloaderInfo->downloadBaseDir, workflowId)) == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + if (ADUC_SystemUtils_MkDirRecursiveDefault(STRING_c_str(targetDir)) != 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_MKDIR_DWNLD_FOLDER; + goto done; + } + + if (IsNullOrEmpty(ADUC_ROOTKEY_PKG_URL_OVERRIDE)) + { + targetUrl = STRING_construct(rootKeyPkgUrl); + } + else + { + targetUrl = STRING_construct(ADUC_ROOTKEY_PKG_URL_OVERRIDE); + } + + if (targetUrl == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + result = ADUC_UrlUtils_GetPathFileName(STRING_c_str(targetUrl), &targetFileName); + if (IsAducResultCodeFailure(result.ResultCode) || IsNullOrEmpty(STRING_c_str(targetFileName))) + { + result.ResultCode = ADUC_GeneralResult_Failure; + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_URL_BAD_PATH; + goto done; + } + + targetFilePath = STRING_construct_sprintf("%s/%s", STRING_c_str(targetDir), STRING_c_str(targetFileName)); + if (targetFilePath == NULL) + { + result.ResultCode = ADUC_GeneralResult_Failure; + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + if (SystemUtils_IsFile(STRING_c_str(targetFilePath), &err)) + { + Log_Warn("rootkey package '%s' in sandbox. Try deletion...", STRING_c_str(targetFileName)); + if (unlink(STRING_c_str(targetFilePath)) != 0) + { + Log_Warn("Fail unlink '%s': %d", STRING_c_str(targetFilePath), errno); + // continue below and try to download anyways. + } + } + + // There is no hash to check so it is a forced download without lookup of + // existing file. Also, the package has self-referential integrity with + // signatures json array of signatures of the protected properties in the + // same json file, so download the file without hash verification. + Log_Debug("Attempting download of '%s' using '%s'", STRING_c_str(targetUrl), downloaderInfo->name); + + result = (*(downloaderInfo->downloadFn))(STRING_c_str(targetUrl), STRING_c_str(targetFilePath)); + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("Unable to download root key pkg."); + goto done; + } + + *outRootKeyPackageDownloadedFile = targetFilePath; + targetFilePath = NULL; + + result.ResultCode = ADUC_GeneralResult_Success; + result.ExtendedResultCode = 0; + +done: + STRING_delete(targetDir); + STRING_delete(targetFileName); + STRING_delete(targetFilePath); + STRING_delete(targetUrl); + + return result; +} + +EXTERN_C_END diff --git a/src/utils/rootkeypackage_utils/src/rootkeypackage_parse.c b/src/utils/rootkeypackage_utils/src/rootkeypackage_parse.c new file mode 100644 index 000000000..78edce42a --- /dev/null +++ b/src/utils/rootkeypackage_utils/src/rootkeypackage_parse.c @@ -0,0 +1,991 @@ +/** + * @file rootkeypackage_parse.c + * @brief rootkeypackage_parse implementation. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "aduc/rootkeypackage_parse.h" +#include "aduc/rootkeypackage_json_properties.h" +#include +#include // for IsNullOrEmpty +#include +#include +#include // for Base64URLDecode +#include // for isnan, isinf + +#if defined(isnan) && defined(isinf) +# define ADUC_IS_NUMBER_INVALID(x) (isnan((x)) || isinf((x))) +#else +# define ADUC_IS_NUMBER_INVALID(x) (((x) * 0.0) != 0.0) +#endif + +/* + Using 0 to indicate invalid RSA exponent since json_object_get_number + returns 0 when the json property value is not json number type and because 0 is + not one of the 5 known Fermat primes of 3, 5, 17, 257 and 65537 for base b = 2 + n generalized Fermat primes. The current root keys use the industry standard of + 65537 (0x010001), or "QAQD" as base64 url encoded string. + */ +#define INVALID_EXPONENT 0 + +EXTERN_C_BEGIN + +/** + * @brief Frees resources for an ADUC_RootKey object. + * + * @param node The pointer to the root key object. + */ +void ADUC_RootKey_DeInit(ADUC_RootKey* node) +{ + if (node == NULL) + { + return; + } + + if (node->kid != NULL) + { + STRING_delete(node->kid); + node->kid = NULL; + } + + node->keyType = ADUC_RootKey_KeyType_INVALID; + + if (node->rsaParameters.n != NULL) + { + CONSTBUFFER_DecRef(node->rsaParameters.n); + node->rsaParameters.n = NULL; + } + + node->rsaParameters.e = 0; +} + +/** + * @brief Deinitializes members of ADUC_RootKeyPackage_Hash node + * + * @param node The node. + */ +void ADUC_RootKeyPackage_Hash_DeInit(ADUC_RootKeyPackage_Hash* node) +{ + if (node == NULL) + { + return; + } + + if (node->hash != NULL) + { + CONSTBUFFER_DecRef(node->hash); + node->hash = NULL; + } +} + +/** + * @brief Deinitializes members of ADUC_RootKeyPackage_Signature node + * + * @param node The node. + */ +void ADUC_RootKeyPackage_Signature_DeInit(ADUC_RootKeyPackage_Signature* node) +{ + if (node == NULL) + { + return; + } + + if (node->signature != NULL) + { + CONSTBUFFER_DecRef(node->signature); + node->signature = NULL; + } +} + +/** + * @brief Parses the isTest protected property in accordance with rootkeypackage.schema.json + * + * @param protectedPropertiesObj The root JSON object. + * @param[out] outPackage The root key package object to write parsed version data. + * + * @return The result. + */ +ADUC_Result RootKeyPackage_ParseIsTest(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + int isTestValue = 0; + + if (protectedPropertiesObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + goto done; + } + + isTestValue = json_object_get_boolean(protectedPropertiesObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_ISTEST); + if (isTestValue == -1) + { + isTestValue = 0; // assume non-test if missing + } + + (outPackage->protectedProperties).isTest = (bool)isTestValue; + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing '" ADUC_ROOTKEY_PACKAGE_PROPERTY_ISTEST "' property.", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses the version protected property in accordance with rootkeypackage.schema.json + * + * @param protectedPropertiesObj The root JSON object. + * @param[out] outPackage The root key package object to write parsed version data. + * + * @return The result. + */ +ADUC_Result RootKeyPackage_ParseVersion(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + double versionNum = 0.0; + + if (protectedPropertiesObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + goto done; + } + + versionNum = json_object_get_number(protectedPropertiesObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_VERSION); + if (versionNum == 0.0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_VERSION; + goto done; + } + + (outPackage->protectedProperties).version = (unsigned long)versionNum; + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing '" ADUC_ROOTKEY_PACKAGE_PROPERTY_VERSION "' property.", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses the published protected property in accordance with rootkeypackage.schema.json + * + * @param protectedPropertiesObj The protected properties JSON object. + * @param[out] outPackage The root key package object to write parsed published data. + * + * @return The result. + */ +ADUC_Result RootKeyPackage_ParsePublished(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + time_t published = 0; + + if (protectedPropertiesObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + published = (time_t)json_object_get_number(protectedPropertiesObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_PUBLISHED); + if (published <= 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PUBLISHED; + goto done; + } + + (outPackage->protectedProperties).publishedTime = published; + result.ResultCode = ADUC_GeneralResult_Success; + +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing '" ADUC_ROOTKEY_PACKAGE_PROPERTY_PUBLISHED "' property.", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses the disabledRootKeys protected property in accordance with rootkeypackage.schema.json + * + * @param protectedPropertiesObj The protected properties JSON object. + * @param[out] outPackage The root key package object to write parsed disabledRootKeys data. + * + * @return The result. + */ +ADUC_Result RootKeyPackage_ParseDisabledRootKeys(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + JSON_Array* kidsArray = NULL; + VECTOR_HANDLE kids = NULL; + size_t count = 0; + + if (protectedPropertiesObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + kidsArray = json_object_get_array(protectedPropertiesObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_DISABLED_ROOT_KEYS); + if (kidsArray == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDROOTKEYS; + goto done; + } + + count = json_array_get_count(kidsArray); + + kids = VECTOR_create(sizeof(STRING_HANDLE)); + if (kids == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + for (size_t i = 0; i < count; ++i) + { + const char* kid = NULL; + STRING_HANDLE kidHandle = NULL; + if ((kid = json_array_get_string(kidsArray, i)) == NULL || (kidHandle = STRING_construct(kid)) == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + if (VECTOR_push_back(kids, &kidHandle, 1) != 0) + { + STRING_delete(kidHandle); + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + kidHandle = NULL; + } + + (outPackage->protectedProperties).disabledRootKeys = kids; + kids = NULL; + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + if (kids != NULL) + { + size_t cnt = VECTOR_size(kids); + for (size_t i = 0; i < cnt; ++i) + { + STRING_HANDLE* h = VECTOR_element(kids, i); + STRING_delete(*h); + } + VECTOR_destroy(kids); + } + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error( + "ERC %d parsing '" ADUC_ROOTKEY_PACKAGE_PROPERTY_DISABLED_ROOT_KEYS "' property.", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses "alg" hash algorithm property. + * + * @param jsonObj The json object with the "alg" property. + * @param outAlg The output parameter to hold the parsed hash algorithm upon success. + * @return ADUC_Result The result. + */ +ADUC_Result RootKeyPackage_ParseHashAlg(JSON_Object* jsonObj, SHAversion* outAlg) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + SHAversion alg = SHA256; + const char* val = NULL; + + if (jsonObj == NULL || outAlg == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + val = json_object_get_string(jsonObj, "alg"); + if (val == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_HASHING_PROPERTY_ALG; + goto done; + } + + if (!ADUC_HashUtils_GetShaVersionForTypeString(val, &alg) || !ADUC_HashUtils_IsValidHashAlgorithm(alg)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_HASH_ALGORITHM; + goto done; + } + + *outAlg = alg; + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing hash '" ADUC_ROOTKEY_PACKAGE_PROPERTY_ALG "' property.", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses "alg" signing algorithm property. + * + * @param jsonObj The json object with the "alg" property. + * @param outAlg The output parameter to hold the parsed signing algorithm upon success. + * @return ADUC_Result The result. + */ +ADUC_Result RootKeyPackage_ParseSigningAlg(JSON_Object* jsonObj, ADUC_RootKeySigningAlgorithm* outAlg) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + ADUC_RootKeySigningAlgorithm alg = ADUC_RootKeySigningAlgorithm_INVALID; + const char* val = NULL; + + if (jsonObj == NULL || outAlg == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + val = json_object_get_string(jsonObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_ALG); + if (val == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_SIGNATURE_PROPERTY_ALG; + goto done; + } + + if (strcmp(val, ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURE_ALG_RS256) == 0) + { + alg = ADUC_RootKeySigningAlgorithm_RS256; + } + else if (strcmp(val, ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURE_ALG_RS384) == 0) + { + alg = ADUC_RootKeySigningAlgorithm_RS384; + } + else if (strcmp(val, ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURE_ALG_RS512) == 0) + { + alg = ADUC_RootKeySigningAlgorithm_RS512; + } + else + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_SIGNING_ALGORITHM; + goto done; + } + + *outAlg = alg; + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing signing '" ADUC_ROOTKEY_PACKAGE_PROPERTY_ALG "' property.", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses a base64 URLUInt value from the JSON object. + * + * @param jsonObj The JSON object with the property that is the hash value. + * @param propertyName The property name for the value containing the Base64 URLUInt encoded data. + * @param outHashBuffer The output parameter const buffer handle for holding the binary data. + * @return ADUC_Result The result. + */ +ADUC_Result RootKeyPackage_ParseBase64URLUIntJsonString( + JSON_Object* jsonObj, const char* propertyName, CONSTBUFFER_HANDLE* outHashBuffer) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + uint8_t* buf = NULL; + size_t out_len = 0; + CONSTBUFFER_HANDLE buffer = NULL; + const char* val = NULL; + + if (jsonObj == NULL || IsNullOrEmpty(propertyName) || outHashBuffer == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + val = json_object_get_string(jsonObj, propertyName); + if (val == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_HASH_OR_SIG; + goto done; + } + + out_len = Base64URLDecode(val, &buf); + if (out_len == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_ENCODING; + goto done; + } + + buffer = CONSTBUFFER_Create(buf, out_len); + if (buffer == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + *outHashBuffer = buffer; + buffer = NULL; + + result.ResultCode = ADUC_GeneralResult_Success; +done: + + free(buf); + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing '%s' property.", result.ResultCode, propertyName); + } + + return result; +} + +/** + * @brief Parses the disabledSigningKeys protected property in accordance with rootkeypackage.schema.json + * + * @param protectedPropertiesObj The protected properties JSON object. + * @param[out] outPackage The root key package object to write parsed disabledSigningKeys data. + * + * @return The result. + */ +ADUC_Result +RootKeyPackage_ParseDisabledSigningKeys(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + JSON_Array* hashesArray = NULL; + VECTOR_HANDLE hashes = NULL; + size_t count = 0; + + if (protectedPropertiesObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + hashesArray = json_object_get_array(protectedPropertiesObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_DISABLED_SIGNING_KEYS); + if (hashesArray == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_DISABLEDSIGNINGKEYS; + goto done; + } + + count = json_array_get_count(hashesArray); + + hashes = VECTOR_create(sizeof(ADUC_RootKeyPackage_Hash)); + if (hashes == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + for (size_t i = 0; i < count; ++i) + { + // These are SHA256 (or stronger) Hash of the public key of signing key. + ADUC_RootKeyPackage_Hash hashElement = { .alg = SHA256, .hash = NULL }; + SHAversion tmpAlg = SHA256; + CONSTBUFFER_HANDLE hashBuf = NULL; + + JSON_Object* hashJsonArrayElementObj = json_array_get_object(hashesArray, i); + if (hashJsonArrayElementObj == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_DISABLEDSIGNINGKEYS_ELEMENT; + goto done; + } + + result = RootKeyPackage_ParseHashAlg(hashJsonArrayElementObj, &tmpAlg); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseBase64URLUIntJsonString( + hashJsonArrayElementObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_HASH, &hashBuf); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + hashElement.alg = tmpAlg; + hashElement.hash = hashBuf; + + if (VECTOR_push_back(hashes, &hashElement, 1) != 0) + { + ADUC_RootKeyPackage_Hash_DeInit(&hashElement); + + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + } + + (outPackage->protectedProperties).disabledSigningKeys = hashes; + hashes = NULL; + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + if (hashes != NULL) + { + size_t cnt = VECTOR_size(hashes); + for (size_t i = 0; i < cnt; ++i) + { + ADUC_RootKeyPackage_Hash* node = (ADUC_RootKeyPackage_Hash*)VECTOR_element(hashes, i); + ADUC_RootKeyPackage_Hash_DeInit(node); + } + + VECTOR_destroy(hashes); + } + + return result; +} + +/** + * @brief Parses the kid-to-rootKeyDefinition mappings in the rootKeys JSON object. + * + * @param rootKeysObj The JSON object with the KIDs that map to root key definition. + * @param index The index into the JSON array. + * @param outRootKeys The vector to add ADUC_RootKey elements. + * @return ADUC_Result The result. + */ +static ADUC_Result ParseRootKey(JSON_Object* rootKeysObj, size_t index, VECTOR_HANDLE* outRootKeys) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + JSON_Object* rootKeyDefinition = NULL; + STRING_HANDLE kidStrHandle = NULL; + ADUC_RootKey_KeyType keyType = ADUC_RootKey_KeyType_INVALID; + CONSTBUFFER_HANDLE rsa_modulus = NULL; + unsigned int rsa_exponent = 0; + + ADUC_RootKey rootKey; + memset(&rootKey, 0, sizeof(rootKey)); + + size_t modulus_len = 0; + uint8_t* modulus_buf = NULL; + + const char* keytypeStr = NULL; + const char* n_modulusStr = NULL; + double e_exponent = INVALID_EXPONENT; + + const char* kid = json_object_get_name(rootKeysObj, index); + if (IsNullOrEmpty(kid)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_KEY_ID; + goto done; + } + + kidStrHandle = STRING_construct(kid); + if (kidStrHandle == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + rootKeyDefinition = json_object_get_object(rootKeysObj, kid); + if (rootKeyDefinition == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UNEXPECTED; + goto done; + } + + keytypeStr = json_object_get_string(rootKeyDefinition, ADUC_ROOTKEY_PACKAGE_PROPERTY_KEY_TYPE); + if (IsNullOrEmpty(keytypeStr)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_KEYTYPE; + goto done; + } + + if (strcmp(keytypeStr, ADUC_ROOTKEY_PACKAGE_PROPERTY_KEY_TYPE_RSA) == 0) + { + keyType = ADUC_RootKey_KeyType_RSA; + n_modulusStr = json_object_get_string(rootKeyDefinition, ADUC_ROOTKEY_PACKAGE_PROPERTY_RSA_MODULUS); + + if (IsNullOrEmpty(n_modulusStr)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_MODULUS; + goto done; + } + + e_exponent = json_object_get_number(rootKeyDefinition, ADUC_ROOTKEY_PACKAGE_PROPERTY_RSA_EXPONENT); + if (e_exponent == INVALID_EXPONENT || ADUC_IS_NUMBER_INVALID(e_exponent)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_EXPONENT; + goto done; + } + + rsa_exponent = (unsigned int)e_exponent; + + modulus_len = Base64URLDecode(n_modulusStr, &modulus_buf); + if (modulus_len == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_INVALID_RSA_PARAMETERS; + goto done; + } + + rsa_modulus = CONSTBUFFER_Create(modulus_buf, modulus_len); + if (rsa_modulus == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + } + else + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_UNSUPPORTED_KEYTYPE; + goto done; + } + + rootKey.kid = kidStrHandle; + rootKey.keyType = keyType; + rootKey.rsaParameters.n = rsa_modulus; + rootKey.rsaParameters.e = rsa_exponent; + + if (VECTOR_push_back(*outRootKeys, &rootKey, 1) != 0) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + // commit transfer + kidStrHandle = NULL; + rsa_modulus = NULL; + memset(&rootKey, 0, sizeof(rootKey)); + result.ResultCode = ADUC_GeneralResult_Success; + +done: + if (kidStrHandle != NULL) + { + STRING_delete(kidStrHandle); + } + + free(modulus_buf); + + if (rsa_modulus != NULL) + { + CONSTBUFFER_DecRef(rsa_modulus); + } + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("Failed parse of rootkey, ERC %d", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses the rootKeys protected property in accordance with rootkeypackage.schema.json + * + * @param protectedPropertiesObj The protected properties JSON object. + * @param[out] outPackage The root key package object to write parsed rootKeys data. + * + * @return The result. + */ +ADUC_Result RootKeyPackage_ParseRootKeys(JSON_Object* protectedPropertiesObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + size_t cnt = 0; + + JSON_Object* rootKeysObj = NULL; + VECTOR_HANDLE rootKeys = NULL; + + if (protectedPropertiesObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + rootKeysObj = json_object_get_object(protectedPropertiesObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_ROOTKEYS); + if (protectedPropertiesObj == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_ROOTKEYS; + goto done; + } + + cnt = json_object_get_count(rootKeysObj); + if (cnt == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_ROOTKEYS_EMPTY; + goto done; + } + + rootKeys = VECTOR_create(sizeof(ADUC_RootKey)); + if (rootKeys == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + for (size_t i = 0; i < cnt; ++i) + { + result = ParseRootKey(rootKeysObj, i, &rootKeys); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + } + + outPackage->protectedProperties.rootKeys = rootKeys; + rootKeys = NULL; + result.ResultCode = ADUC_GeneralResult_Success; + +done: + if (rootKeys != NULL) + { + size_t root_key_vec_size = VECTOR_size(rootKeys); + for (size_t i = 0; i < root_key_vec_size; ++i) + { + ADUC_RootKey* node = (ADUC_RootKey*)VECTOR_element(rootKeys, i); + ADUC_RootKey_DeInit(node); + } + + VECTOR_destroy(rootKeys); + } + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing 'protected' property.", result.ResultCode); + } + + return result; +} + +/** + * @brief Parses the protected properties in accordance with rootkeypackage.schema.json + * + * @param protectedPropertiesObj The protected properties JSON object. + * @param[out] outPackage The root key package object to write parsed protected properties data. + * + * @return The result. + */ +ADUC_Result RootKeyPackage_ParseProtectedProperties(JSON_Object* rootObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + JSON_Object* protectedPropertiesObj = NULL; + + if (rootObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + protectedPropertiesObj = json_object_get_object(rootObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_PROTECTED); + if (protectedPropertiesObj == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PROTECTED; + goto done; + } + + result = RootKeyPackage_ParseIsTest(protectedPropertiesObj, outPackage); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseVersion(protectedPropertiesObj, outPackage); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParsePublished(protectedPropertiesObj, outPackage); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseDisabledRootKeys(protectedPropertiesObj, outPackage); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseDisabledSigningKeys(protectedPropertiesObj, outPackage); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseRootKeys(protectedPropertiesObj, outPackage); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing 'protected' property.", result.ResultCode); + } + + return result; +} + +ADUC_Result RootKeyPackage_ParseProtectedPropertiesString(JSON_Object* rootObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + STRING_HANDLE protectedPropertiesStringHandle = NULL; + JSON_Value* protectedPropertiesValue = NULL; + char* protectedPropertiesString = NULL; + + if (rootObj == NULL || outPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + goto done; + } + + protectedPropertiesValue = json_object_get_value(rootObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_PROTECTED); + + if (protectedPropertiesValue == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_PROTECTED; + goto done; + } + + protectedPropertiesString = json_serialize_to_string(protectedPropertiesValue); + + if (protectedPropertiesString == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + protectedPropertiesStringHandle = STRING_construct(protectedPropertiesString); + + if (protectedPropertiesStringHandle == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; + outPackage->protectedPropertiesJsonString = protectedPropertiesStringHandle; + protectedPropertiesStringHandle = NULL; + +done: + free(protectedPropertiesString); + STRING_delete(protectedPropertiesStringHandle); + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("ERC %d parsing 'protected' property to string", result.ResultCode); + } + + return result; +} +/** + * @brief Parses the signatures properties in accordance with rootkeypackage.schema.json + * + * @param rootObj The root JSON object. + * @param[out] outPackage The root key package object to write parsed signatures data. + * + * @return The result. + */ +ADUC_Result RootKeyPackage_ParseSignatures(JSON_Object* rootObj, ADUC_RootKeyPackage* outPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + VECTOR_HANDLE signatures = NULL; + + JSON_Array* signaturesArray = json_object_get_array(rootObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURES); + if (signaturesArray == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_MISSING_REQUIRED_PROPERTY_SIGNATURES; + goto done; + } + + size_t cnt = json_array_get_count(signaturesArray); + if (cnt == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_SIGNATURES_EMPTY; + goto done; + } + + signatures = VECTOR_create(sizeof(ADUC_RootKeyPackage_Signature)); + if (signatures == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + for (size_t i = 0; i < cnt; ++i) + { + ADUC_RootKeyPackage_Signature signatureElement = { .alg = ADUC_RootKeySigningAlgorithm_INVALID, + .signature = NULL }; + ADUC_RootKeySigningAlgorithm tmpAlg = ADUC_RootKeySigningAlgorithm_INVALID; + CONSTBUFFER_HANDLE signatureBuf = NULL; + + JSON_Object* hashJsonArrayElementObj = json_array_get_object(signaturesArray, i); + if (hashJsonArrayElementObj == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_PARSE_GETOBJ_SIGNATURES_ELEMENT; + goto done; + } + + result = RootKeyPackage_ParseSigningAlg(hashJsonArrayElementObj, &tmpAlg); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseBase64URLUIntJsonString( + hashJsonArrayElementObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_SIG, &signatureBuf); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + signatureElement.alg = tmpAlg; + signatureElement.signature = signatureBuf; + + if (VECTOR_push_back(signatures, &signatureElement, 1) != 0) + { + // can't add to vector, so free it + CONSTBUFFER_DecRef(signatureElement.signature); + signatureElement.signature = NULL; + + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + memset(&signatureElement, 0, sizeof(signatureElement)); + } + + outPackage->signatures = signatures; + signatures = NULL; + + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (signatures != NULL) + { + size_t sig_cnt = VECTOR_size(signatures); + for (size_t i = 0; i < sig_cnt; ++i) + { + ADUC_RootKeyPackage_Signature* node = (ADUC_RootKeyPackage_Signature*)VECTOR_element(signatures, i); + ADUC_RootKeyPackage_Signature_DeInit(node); + } + + VECTOR_destroy(signatures); + } + + return result; +} + +EXTERN_C_END diff --git a/src/utils/rootkeypackage_utils/src/rootkeypackage_utils.c b/src/utils/rootkeypackage_utils/src/rootkeypackage_utils.c new file mode 100644 index 000000000..cab9a778b --- /dev/null +++ b/src/utils/rootkeypackage_utils/src/rootkeypackage_utils.c @@ -0,0 +1,681 @@ +/** + * @file rootkeypackage_utils.c + * @brief rootkeypackage_utils implementation. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#include "aduc/rootkeypackage_utils.h" +#include "aduc/rootkeypackage_json_properties.h" +#include "aduc/rootkeypackage_parse.h" +#include // for EXTERN_C_BEGIN, EXTERN_C_END, HTTP_URL_HANDLE +#include // for IsNullOrEmpty +#include +#include +#include +#include +#include // tolower +#include + +EXTERN_C_BEGIN + +/** + * @brief Parses JSON string into an ADUC_RootKeyPackage struct. + * + * @param jsonString The root key package JSON string to parse. + * @param outRootKeyPackage parameter for the resultant ADUC_RootKeyPackage. + * + * @return ADUC_Result The result of parsing. + * @details Caller must call ADUC_RootKeyPackageUtils_Cleanup() on the resultant ADUC_RootKeyPackage. + */ +ADUC_Result ADUC_RootKeyPackageUtils_Parse(const char* jsonString, ADUC_RootKeyPackage* outRootKeyPackage) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + ADUC_RootKeyPackage pkg; + memset(&pkg, 0, sizeof(pkg)); + + JSON_Value* rootValue = NULL; + JSON_Object* rootObj = NULL; + + if (IsNullOrEmpty(jsonString) || outRootKeyPackage == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG; + return result; + } + + rootValue = json_parse_string(jsonString); + if (rootValue == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_JSON; + goto done; + } + + rootObj = json_object(rootValue); + if (rootObj == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_JSON; + goto done; + } + + result = RootKeyPackage_ParseProtectedProperties(rootObj, &pkg); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseProtectedPropertiesString(rootObj, &pkg); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = RootKeyPackage_ParseSignatures(rootObj, &pkg); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + *outRootKeyPackage = pkg; + memset(&pkg, 0, sizeof(pkg)); + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + json_value_free(rootValue); + + if (IsAducResultCodeFailure(result.ResultCode)) + { + ADUC_RootKeyPackageUtils_Destroy(&pkg); + } + + return result; +} + +/** + * @brief Helper function for comparing two ADUC_RootKeys + * + * @param lKey left root key to compare + * @param rKey right root key to compare + * @return True if equal; false if not + */ +_Bool ADUC_RootKeyPackageUtils_RootKeysAreEqual(const ADUC_RootKey* lKey, const ADUC_RootKey* rKey) +{ + if (lKey == rKey) + { + return true; + } + else if (lKey == NULL || rKey == NULL) + { + return false; + } + + if (STRING_compare(lKey->kid, rKey->kid) != 0) + { + return false; + } + + if (lKey->keyType != rKey->keyType) + { + return false; + } + + if (lKey->rsaParameters.e != rKey->rsaParameters.e) + { + return false; + } + + return CONSTBUFFER_HANDLE_contain_same(lKey->rsaParameters.n, rKey->rsaParameters.n); +} + +/** + * @brief Helper function for comparing two ADUC_RootKeyPackage_Hashes + * + * @param lKey left hash to compare + * @param rKey right hash to compare + * @return True if equal; false if not + */ +_Bool ADUC_RootKeyPackageUtils_RootKeyPackage_Hash_AreEqual( + const ADUC_RootKeyPackage_Hash* lHash, const ADUC_RootKeyPackage_Hash* rHash) +{ + if (lHash == rHash) + { + return true; + } + else if (lHash == NULL || rHash == NULL) + { + return false; + } + + if (lHash->alg != rHash->alg) + { + return false; + } + + return CONSTBUFFER_HANDLE_contain_same(lHash->hash, rHash->hash); +} + +/** + * @brief Helper function for comparing two ADUC_RootKeyPackage_ProtectedProperties + * + * @param lKey left ADUC_RootKeyPackage_ProtectedProperties to compare + * @param rKey right ADUC_RootKeyPackage_ProtectedProperties to compare + * @return True if equal; false if not + */ +_Bool ADUC_RootKeyPackageUtils_ProtectedProperties_AreEqual( + const ADUC_RootKeyPackage_ProtectedProperties* lProp, const ADUC_RootKeyPackage_ProtectedProperties* rProp) +{ + if (lProp == rProp) + { + return true; + } + else if (lProp == NULL || rProp == NULL) + { + return false; + } + + if (lProp->version != rProp->version) + { + return false; + } + + if (lProp->publishedTime != rProp->publishedTime) + { + return false; + } + + const size_t lPackNumDisabledRootKeys = VECTOR_size(lProp->disabledRootKeys); + const size_t rPackNumDisabledRootKeys = VECTOR_size(rProp->disabledRootKeys); + + if (lPackNumDisabledRootKeys != rPackNumDisabledRootKeys) + { + return false; + } + + for (size_t i = 0; i < lPackNumDisabledRootKeys; ++i) + { + STRING_HANDLE* lKeyId = VECTOR_element(lProp->disabledRootKeys, i); + STRING_HANDLE* rKeyId = VECTOR_element(rProp->disabledRootKeys, i); + + if (STRING_compare(*lKeyId, *rKeyId) != 0) + { + return false; + } + } + + const size_t lPackNumDisabledSigningKeys = VECTOR_size(lProp->disabledSigningKeys); + const size_t rPackNumDisabledSigningKeys = VECTOR_size(rProp->disabledSigningKeys); + + if (lPackNumDisabledSigningKeys != rPackNumDisabledSigningKeys) + { + return false; + } + + for (size_t i = 0; i < lPackNumDisabledSigningKeys; ++i) + { + ADUC_RootKeyPackage_Hash* lPackHash = VECTOR_element(lProp->disabledSigningKeys, i); + ADUC_RootKeyPackage_Hash* rPackHash = VECTOR_element(rProp->disabledSigningKeys, i); + + if (!ADUC_RootKeyPackageUtils_RootKeyPackage_Hash_AreEqual(lPackHash, rPackHash)) + { + return false; + } + } + + const size_t lPackNumRootKeys = VECTOR_size(lProp->rootKeys); + const size_t rPackNumRootKeys = VECTOR_size(rProp->rootKeys); + + if (lPackNumRootKeys != rPackNumRootKeys) + { + return false; + } + + for (size_t i = 0; i < lPackNumRootKeys; ++i) + { + ADUC_RootKey* lPackRootKey = VECTOR_element(lProp->rootKeys, i); + ADUC_RootKey* rPackRootKey = VECTOR_element(rProp->rootKeys, i); + + if (!ADUC_RootKeyPackageUtils_RootKeysAreEqual(lPackRootKey, rPackRootKey)) + { + return false; + } + } + return true; +} + +/** + * @brief Helper function for comparing two ADUC_RootKeyPackage_Signature + * + * @param lKey left ADUC_RootKeyPackage_Signature to compare + * @param rKey right ADUC_RootKeyPackage_Signature to compare + * @return True if equal; false if not + */ +_Bool ADUC_RootKeyPackageUtils_RootKeyPackage_Signatures_AreEqual( + const ADUC_RootKeyPackage_Signature* lSigs, const ADUC_RootKeyPackage_Signature* rSigs) +{ + if (lSigs == rSigs) + { + return true; + } + else if (lSigs == NULL || rSigs == NULL) + { + return false; + } + + if (lSigs->alg != rSigs->alg) + { + return false; + } + return CONSTBUFFER_HANDLE_contain_same(lSigs->signature, rSigs->signature); +} + +/** + * @brief Checks to see if the two packages are correct + * + * @param lPack a package to compare + * @param rPack the other package to compare + * @return true if equal, false otherwise + */ +_Bool ADUC_RootKeyPackageUtils_AreEqual(const ADUC_RootKeyPackage* lPack, const ADUC_RootKeyPackage* rPack) +{ + if (STRING_compare(lPack->protectedPropertiesJsonString, rPack->protectedPropertiesJsonString) != 0) + { + return false; + } + + if (!ADUC_RootKeyPackageUtils_ProtectedProperties_AreEqual( + &lPack->protectedProperties, &rPack->protectedProperties)) + { + return false; + } + + const size_t lPackNumSignatures = VECTOR_size(lPack->signatures); + const size_t rPackNumSignatures = VECTOR_size(rPack->signatures); + + if (lPackNumSignatures != rPackNumSignatures) + { + return false; + } + + for (size_t i = 0; i < lPackNumSignatures; ++i) + { + ADUC_RootKeyPackage_Signature* lSig = VECTOR_element(lPack->signatures, i); + ADUC_RootKeyPackage_Signature* rSig = VECTOR_element(rPack->signatures, i); + + if (!ADUC_RootKeyPackageUtils_RootKeyPackage_Signatures_AreEqual(lSig, rSig)) + { + return false; + } + } + + return true; +} + +STRING_HANDLE RootKeyPackage_SigningAlgToString(const ADUC_RootKeySigningAlgorithm alg) +{ + STRING_HANDLE algStr = NULL; + + switch (alg) + { + case ADUC_RootKeySigningAlgorithm_RS256: + algStr = STRING_construct("RS256"); + break; + case ADUC_RootKeySigningAlgorithm_RS384: + algStr = STRING_construct("RS384"); + break; + case ADUC_RootKeySigningAlgorithm_RS512: + algStr = STRING_construct("RS512"); + break; + case ADUC_RootKeySigningAlgorithm_INVALID: + default: + break; + } + + return algStr; +} + +JSON_Value* ADUC_RootKeyPackageUtils_SignatureToJsonValue(const ADUC_RootKeyPackage_Signature* signature) +{ + _Bool success = true; + JSON_Value* sigJsonValue = NULL; + char* encodedSignature = NULL; + STRING_HANDLE algString = NULL; + + sigJsonValue = json_value_init_object(); + + if (sigJsonValue == NULL) + { + goto done; + } + + JSON_Object* sigJsonObj = json_value_get_object(sigJsonValue); + + const CONSTBUFFER* decodedSig = CONSTBUFFER_GetContent(signature->signature); + + if (decodedSig == NULL || decodedSig->size == 0) + { + goto done; + } + + encodedSignature = Base64URLEncode(decodedSig->buffer, decodedSig->size); + + if (encodedSignature == NULL) + { + goto done; + } + + JSON_Status jsonStatus = json_object_set_string(sigJsonObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_SIG, encodedSignature); + + if (jsonStatus != JSONSuccess) + { + goto done; + } + + algString = RootKeyPackage_SigningAlgToString(signature->alg); + + if (algString == NULL) + { + goto done; + } + + jsonStatus = json_object_set_string(sigJsonObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_ALG, STRING_c_str(algString)); + +done: + + if (!success) + { + if (sigJsonValue != NULL) + { + json_value_free(sigJsonValue); + sigJsonValue = NULL; + } + } + + if (algString != NULL) + { + STRING_delete(algString); + } + + free(encodedSignature); + + return sigJsonValue; +} +/** + * @brief Serializes the ADUC_RootKeyPackage's contents to JSON in string form + * @details it is the duty of the caller to free the returned string + * @param rootKeyPackage root key package to serialize + * @return the serialized version of the root key package in string form + */ +char* ADUC_RootKeyPackageUtils_SerializePackageToJsonString(const ADUC_RootKeyPackage* rootKeyPackage) +{ + JSON_Value* rootKeyPackageJsonValue = NULL; + + JSON_Value* protectedPropertiesJsonValue = NULL; + + JSON_Value* rootKeySignatureArrayValue = NULL; + + VECTOR_HANDLE sigJsonValueVector = NULL; + + char* retString = NULL; + + if (rootKeyPackage == NULL) + { + goto done; + } + + rootKeyPackageJsonValue = json_value_init_object(); + + if (rootKeyPackageJsonValue == NULL) + { + goto done; + } + + JSON_Object* rootKeyPackageJsonObj = json_value_get_object(rootKeyPackageJsonValue); + + if (rootKeyPackage->protectedPropertiesJsonString == NULL + || STRING_length(rootKeyPackage->protectedPropertiesJsonString) == 0) + { + goto done; + } + + protectedPropertiesJsonValue = json_parse_string(STRING_c_str(rootKeyPackage->protectedPropertiesJsonString)); + + if (protectedPropertiesJsonValue == NULL) + { + goto done; + } + + if (json_object_set_value( + rootKeyPackageJsonObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_PROTECTED, protectedPropertiesJsonValue) + != JSONSuccess) + { + goto done; + } + + // + // commit to giving up ownership + // + protectedPropertiesJsonValue = NULL; + + rootKeySignatureArrayValue = json_value_init_array(); + if (rootKeySignatureArrayValue == NULL) + { + goto done; + } + + JSON_Array* signatureArray = json_value_get_array(rootKeySignatureArrayValue); + + if (signatureArray == NULL) + { + goto done; + } + + const size_t numSignatures = VECTOR_size(rootKeyPackage->signatures); + + for (size_t i = 0; i < numSignatures; ++i) + { + ADUC_RootKeyPackage_Signature* signature = + (ADUC_RootKeyPackage_Signature*)VECTOR_element(rootKeyPackage->signatures, i); + + if (signature == NULL) + { + goto done; + } + + JSON_Value* sigJsonValue = ADUC_RootKeyPackageUtils_SignatureToJsonValue(signature); + + if (json_array_append_value(signatureArray, sigJsonValue) != JSONSuccess) + { + goto done; + } + } + + if (json_object_set_value( + rootKeyPackageJsonObj, ADUC_ROOTKEY_PACKAGE_PROPERTY_SIGNATURES, rootKeySignatureArrayValue) + != JSONSuccess) + { + goto done; + } + + // + // Commit to giving up ownership + // + rootKeySignatureArrayValue = NULL; + + retString = json_serialize_to_string(rootKeyPackageJsonValue); + + if (retString == NULL) + { + goto done; + } + +done: + + if (protectedPropertiesJsonValue != NULL) + { + json_value_free(protectedPropertiesJsonValue); + } + + if (rootKeySignatureArrayValue != NULL) + { + json_value_free(rootKeySignatureArrayValue); + } + + if (rootKeyPackageJsonValue != NULL) + { + json_value_free(rootKeyPackageJsonValue); + } + + if (sigJsonValueVector != NULL) + { + const size_t sigJsonValueVectorSz = VECTOR_size(sigJsonValueVector); + + for (size_t i = 0; i < sigJsonValueVectorSz; ++i) + { + JSON_Value** sigValuePtr = (JSON_Value**)VECTOR_element(sigJsonValueVector, i); + + json_value_free(*sigValuePtr); + } + VECTOR_destroy(sigJsonValueVector); + } + + return retString; +} + +/** + * @brief Cleans up the disabled root keys in the rootkey package. + * + * @param rootKeyPackage The root key package. + */ +void ADUC_RootKeyPackageUtils_DisabledRootKeys_Destroy(ADUC_RootKeyPackage* rootKeyPackage) +{ + if (rootKeyPackage == NULL) + { + return; + } + + VECTOR_HANDLE vec = rootKeyPackage->protectedProperties.disabledRootKeys; + if (vec != NULL) + { + size_t cnt = VECTOR_size(vec); + for (size_t i = 0; i < cnt; ++i) + { + STRING_HANDLE* h = (STRING_HANDLE*)VECTOR_element(vec, i); + if (h != NULL) + { + STRING_delete(*h); + } + } + VECTOR_destroy(rootKeyPackage->protectedProperties.disabledRootKeys); + rootKeyPackage->protectedProperties.disabledRootKeys = NULL; + } +} + +/** + * @brief Cleans up the disabled signing keys in the rootkey package. + * + * @param rootKeyPackage The root key package. + */ +void ADUC_RootKeyPackageUtils_DisabledSigningKeys_Destroy(ADUC_RootKeyPackage* rootKeyPackage) +{ + if (rootKeyPackage == NULL) + { + return; + } + + VECTOR_HANDLE vec = rootKeyPackage->protectedProperties.disabledSigningKeys; + if (vec != NULL) + { + size_t cnt = VECTOR_size(vec); + for (size_t i = 0; i < cnt; ++i) + { + ADUC_RootKeyPackage_Hash* node = (ADUC_RootKeyPackage_Hash*)VECTOR_element(vec, i); + ADUC_RootKeyPackage_Hash_DeInit(node); + } + + VECTOR_destroy(rootKeyPackage->protectedProperties.disabledSigningKeys); + rootKeyPackage->protectedProperties.disabledSigningKeys = NULL; + } +} + +/** + * @brief Cleans up the root keys in the rootkey package. + * + * @param rootKeyPackage The root key package. + */ +void ADUC_RootKeyPackageUtils_RootKeys_Destroy(ADUC_RootKeyPackage* rootKeyPackage) +{ + if (rootKeyPackage == NULL) + { + return; + } + + VECTOR_HANDLE vec = rootKeyPackage->protectedProperties.rootKeys; + if (vec != NULL) + { + size_t cnt = VECTOR_size(vec); + for (size_t i = 0; i < cnt; ++i) + { + ADUC_RootKey* rootKeyEntry = (ADUC_RootKey*)VECTOR_element(vec, i); + ADUC_RootKey_DeInit(rootKeyEntry); + } + VECTOR_destroy(rootKeyPackage->protectedProperties.rootKeys); + rootKeyPackage->protectedProperties.rootKeys = NULL; + } +} + +/** + * @brief Cleans up the signatures in the rootkey package. + * + * @param rootKeyPackage The root key package. + */ +void ADUC_RootKeyPackageUtils_Signatures_Destroy(ADUC_RootKeyPackage* rootKeyPackage) +{ + if (rootKeyPackage == NULL) + { + return; + } + + VECTOR_HANDLE vec = rootKeyPackage->signatures; + if (vec != NULL) + { + size_t cnt = VECTOR_size(vec); + for (size_t i = 0; i < cnt; ++i) + { + ADUC_RootKeyPackage_Signature* node = (ADUC_RootKeyPackage_Signature*)VECTOR_element(vec, i); + ADUC_RootKeyPackage_Signature_DeInit(node); + } + + VECTOR_destroy(rootKeyPackage->signatures); + rootKeyPackage->signatures = NULL; + } +} + +/** + * @brief Cleans up an ADUC_RootKeyPackage object. + * + * @param rootKeyPackage The root key package object to cleanup. + */ +void ADUC_RootKeyPackageUtils_Destroy(ADUC_RootKeyPackage* rootKeyPackage) +{ + if (rootKeyPackage == NULL) + { + return; + } + + ADUC_RootKeyPackageUtils_DisabledRootKeys_Destroy(rootKeyPackage); + ADUC_RootKeyPackageUtils_DisabledSigningKeys_Destroy(rootKeyPackage); + ADUC_RootKeyPackageUtils_RootKeys_Destroy(rootKeyPackage); + + ADUC_RootKeyPackageUtils_Signatures_Destroy(rootKeyPackage); + + if (rootKeyPackage->protectedPropertiesJsonString != NULL) + { + STRING_delete(rootKeyPackage->protectedPropertiesJsonString); + rootKeyPackage->protectedPropertiesJsonString = NULL; + } + + memset(rootKeyPackage, 0, sizeof(*rootKeyPackage)); +} + +EXTERN_C_END diff --git a/src/utils/rootkeypackage_utils/tests/CMakeLists.txt b/src/utils/rootkeypackage_utils/tests/CMakeLists.txt new file mode 100644 index 000000000..e97a6264f --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/CMakeLists.txt @@ -0,0 +1,35 @@ +set (target_name rootkeypackage_utils_unit_test) + +include (agentRules) + +compileasc99 () +disablertti () + +find_package (Catch2 REQUIRED) +find_package (Parson REQUIRED) + +add_executable (${target_name}) +target_sources (${target_name} PRIVATE src/main.cpp src/rootkeypackage_utils_ut.cpp + src/rootkeypackage_download_ut.cpp) + +target_link_aziotsharedutil (${target_name} PRIVATE) +target_include_directories (${target_name} PRIVATE inc) + +target_link_libraries ( + ${target_name} + PRIVATE aduc::rootkeypackage_utils + aduc::test_utils + aduc::crypto_utils + aduc::c_utils + aduc::hash_utils + aduc::system_utils + Catch2::Catch2 + Parson::parson) + +target_compile_definitions (${target_name} PRIVATE ADUC_TEST_DATA_FOLDER="${ADUC_TEST_DATA_FOLDER}") + +include (CTest) +include (Catch) +catch_discover_tests (${target_name}) + +add_subdirectory (testapp) diff --git a/src/utils/rootkeypackage_utils/tests/inc/rootkeypkgtestutils.hpp b/src/utils/rootkeypackage_utils/tests/inc/rootkeypkgtestutils.hpp new file mode 100644 index 000000000..38bf48499 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/inc/rootkeypkgtestutils.hpp @@ -0,0 +1,361 @@ +#ifndef ROOTKEYPKGTESTUTILS_HPP +#define ROOTKEYPKGTESTUTILS_HPP + +#include +#include +#include +namespace aduc +{ +namespace rootkeypkgtestutils +{ +constexpr size_t NumTestRootKeys = 3; +enum class rootkeys +{ + rootkey1 = 0, + rootkey2 = 1, + rootkey3 = 2, +}; + +static std::string privgens[NumTestRootKeys] = { + // Root 1 + "MIIEowIBAAKCAQEArSzp0Z8xFFs6f3SixM_iFni-HG5Gfdsfjm7fKNSnRHmC656o" + "azWTpUgC0GCrzs8xYwIRoTyFbIQZAQf4cJpA2EKVIkWxPslHuXUmCGRFGtoOp-m_" + "YEgZ2T36NG0dbFOuzPDGLnUw2EwyZrPZqLPKIwsWP6qHgI0FRWyR7FQoGfYqjjKs" + "bS2Xt2oFkDt8121XKYrxLIWe3gYgUstwqCdzT82rAtzpLvMVD74Rte5qHfb8XD2u" + "ntlmmnpE9jMyhzYOdNqsUYuGTy3NBAJNg5OgAVAINWrcoFJaSNjlBZuHYtk7414o" + "2DSkbppI5mWil_l5u4rSYQWjIHWhzqd7cdJ6bwIDAQABAoIBACIAo5hpLXXVw9Kq" + "0BrcxoOrCYkDjgvALp4E3wRhXMZxJWemK2OBjY_yZ7sKgDGHNSc_jL6f54K7HT26" + "lullID5WNHoaPQca9l5Pxjv3lCoFjsMhflYlUg35wVrx4ckXVUcgL4mHsSOHMo4_" + "2gjp5FKlJqUxkpGHHvXWr4A7tfQCsv8-Ue_t1wQpC6g1j7K0d9M3_LN8BF037h2x" + "sWYsXa80zY9CT_knJtTXbAL2DI6xJH5CHX8KCf5t2gGdssveKqP2dHhR6PlItlW_" + "nqBw8lJobhpPBEookgbSGdTbms2ODBg5TwO7GFudCYb1EnAyvdjdHXxJJgMzC4hL" + "0-YhvYECgYEA1WPdvQfRISSPrHU7wpw9-r-kKsgM3F8op6nSejjtD87mhnaOIqlq" + "Wk90dMLlv0l-pfslIWYQnRWFZJ3SJzEgwV6tuHQqZQs7H8n_r00sYnxvM1jaChR5" + "PNUp8-xcXWlTQezUO5B053WW04HPSp-hLO2licbADHbN-nbtOCDgr78CgYEAz8FX" + "2yN5xMIe3iI3WpL0lSiSgRdY2i9ckcYuYIN8M6-lFBMI16QwUcnzflgisto-0bxm" + "EJS0jdO9uHzU0issAqO4wt6a9PT5SgY_AnqHpyGC1zHFSq8-LKnLGWKq_3UXA07X" + "c0SGH1sawIOSGSiLli6upZm98XQUECi1zYC84VECgYA7vdXaklGuYboHolq0xWFk" + "zjp7774KBGoxZo4SwdU808QeaRqqAZxQ5GXKOrZvs3fNqF5g115XXCsYXEb1yf9N" + "o-Am__7OgzJuV_NJdOW0PPo0-e8xW0IGEffI3qeNT2uLzW4trufL1VQAqxsJ3V8W" + "YQIzbH1f__Ly6FDJogrFqQKBgQClLam2d4w3HcgBAN9VygVgGjPxIyjnwEQvOoxg" + "--liBsKPJVsgaFBqltBboaNk5BSSGOJlSHYNVU5AQi_LMbv6FUWu2eIF5EfXzQOH" + "6vezr_chNVcRPCeIxy7Nbh9aoDO904-E-_RPNdYdPf6Iti3VKCR_Ua8tLAdPma6C" + "R1rlIQKBgAlZgxM_Zi5-cMsoPGsGvzX5a_u1JMCdm3Auc5Q3KU9CEZQgPzv2Ta77" + "W2bBGvpviUYDEzzTQvqio--BjB3plsgwFYOnWVLMXBEhCw8IyhymyrGk1Vn8_V-w" + "ODtCHfNYJCtdxLN2P3m_yTecBbGJNbYFh53NzgaBl76Ssav0QEk9", + + // Root 2 + "MIIEpQIBAAKCAQEAyZtxZnkBrmZzFF7GNA9XYUFaBSl1MqcLEgqGW9PUyS48LK5r" + "7PBXDCnF4e5u04VcKJ2PKPLHwRv9_ZGYQeeVJYVoBIomEOISXXXHKf90PwYKswFq" + "XILzB9AaYUvftgp2mubfVj94Eiq5GKvFwr7yqY3Yqj6tSSWNi6eV-FJt4ypth4CI" + "pyZPrrixnvI02gUOSF1Xwwk8PVgM2a_9FKWflFSYeN7p97ORkdXnA82XeYX9h2RH" + "MomtZMCCtNpjWmioLgUXyQeS6Qq1Q2wfAPOZq-amHayq_Dxy5db9KbIe13AdbEv2" + "BCoQlyL1fKSBQWiRGhkSxPwrKuseLp90j1xjhQIDAQABAoIBAQCb60D3rGw1cfxc" + "a7PEPX0ptT4msdp28yOnr0YcLKbrdHuLXtYPKA1aVdA5nIpPwlr0-m3mkGUWn0x-" + "2CQ2DCGYJCW_JQytj_n-GAGRJITF3SlXKagVphzJFRPh3alFg7AYuqdNb8av3iTK" + "xMYsiDrqEM7ZU6H26TkgIdrlcvKTdTQ23c3-mAWYjfk_RysNACCSe2rtrjGNFRYm" + "Sgt0uXVn_xJWHiMPGK_NrPea1TluN5Y0QXzV1LPEKlMG1c1-s9F30MA4cC3QfHot" + "r96cD83YJRjWj_8U7TyMcqNahRQi8L0qBIKM5IRq3BmgWsGRgYtqcbbSoI0rAh2E" + "6FlLLR4dAoGBAOnIFEbC8lJ-S-hgZzhGZUnIroI7tvxVr1UBzxLJNE0laVDaLbnj" + "ymCMt-o3dwUQ3gx6aIlEU_6STPq5YUdEqc_5LJ1rSOUC3jL_QIHOGKFpLBvicp8u" + "aqW_QZ2Gt2l9-ha5CnAw0NZDhB5-yxx87gI1TQcKS7-UpAK6lU_jy65rAoGBANzE" + "jzhB7PveNIA-Z4nWMVqmqkQe2Y87QG7aKmVF2MgyDfEWq-3Ui3giK6dPLhvMbfTM" + "mOb7WWOZ4wq3bfSzhqYA12gz2fj52GOwGcsXMe9bObGsv9veAC41ZDmnXxCGxwkV" + "3pb8djUxcGZ3rX4Pg057G7sjDAXOMZu9EJeUD9HPAoGBAOOz_pPho5bX7uV6qG72" + "mgdg0SCGOzfR2YHJzkB0-1082DRpHeqWRXL-_M_DkEi94hlzTMiOZeVp6FK5J1f8" + "OA4am-sEKS7uOTCgz9reu7zTrKPIT25eDoA8JhPhuFmm22UwfEtEMNTRVClDxF-O" + "C2DZO5pk29zRUWJbC72RmbzbAoGBAJ8RjbRWZB_ysld5H3dEexk7H1Gn_NBkO__j" + "eEqyMgnFbyA4WrcpvzhXPqb1uV5URSHuzXkYwAaxGdNd6X84X5t63bp6KeNoek8R" + "0vPviY5SZ9aqhy8v3WduFwIno6qvwfe85z5ZN_8J2VgrgTlkihLhR1DmZsJEGKCD" + "cNIW3_MnAoGAfTIFiaOEo9hhIb0RJQc9ZXhcYwZq9uuS4BlhhLrOOGGJlADwJmg5" + "JeSNt0TjKTG0AOJwu_O-uHkpErskagBdnwdf08WtrLsxWq__0WYAglbrZ12goG4_" + "2iXoA9rS4bQ0ybxQMU9nLC6rHq4ktNNbcV61hjdRG94rrIRon6phuh0", + + // Root 3 + "MIIEpQIBAAKCAQEAwRy4kb2eXFXyTPVGewfBbZVNoOoLOLKdqxLvnFl7-9jwWwS4" + "9GNZ8kpfO3nCU1qsoD198fLaTBvz9GVnsmrjpxLuA8im8Rq8O56kNs2XUDqftCFG" + "CCSBqbDww4vcHuTdeQF3xqzL2ezIe4hDqF3r3Uu7VkzNmLhIccW03SEB7xDYH7ta" + "t_6nAE_CuToqQh3V8gTQulRckONhAGG3CK_5DqHpk_GU8AFmWO8um2bPyTGW9pQG" + "cQj5TieLpIWZmS6r8_NyF056B7b9PZ10ZozkLTdUVvEy3dMeQXLVJBn3ZpccZB6M" + "8UaD1UMW7HXEn0saro506cMWdx06g6EMRv3GbwIDAQABAoIBADAHoLA-5SA6ECWr" + "63e2GhnTRJd9HoVfh2-BKi9M4lVlQ4KfzhCalUh5zu3P_tEUgFLqeGSw7jJ30Vk7" + "z2rEwxJO1vwB7-OPrrl1X4px3-yIaCg5Dl4AFm_KHlfEdV8JtTvfbZbwa1MsXUC8" + "R3ecxIkpyNJSD-CoFPyXG8DT8NMwgjwQnfY2Zr3VO4x21JtXJgeX3F47Ve5ChTQ3" + "Af87PDqsiJC6PLwInKXfhZm2zXWowY_3-5IrT3JL_mrCFhv5xihQWo6mjalyR-5J" + "3jBb4KGkAB57AtVwjB1NYm2lA2yVww0GejT1cq1GPMcyuOd5OPlncPfDH7DkP8uw" + "A1SQI8ECgYEA8_9-Qc1e7G5_yt_RTki3w2tPcmqvkAO_OKuBlAvyg0w9ftFLi8YF" + "EQYLTYVc87U3IYfWezqMgI6tW9_cu4WVIUObGlfobSQmlDO3wIcnIt1GdrMIX7AY" + "AE3r-ITK4_phw4ySEDL-ICnAl6hqaiY_7pkZXbRVf7B9Y9UIuAWIyfkCgYEAypx0" + "udJ-m0fO8PmZl6cK9XWXVw2_fvDlR_NvZiv2gsvdzR6zpS2ryOCdNnEfzC1Cx3eC" + "4A06zBZujaTdHzDQWhg2oAI5UOzc19kOZ2IZCKeBRCB_1B0n1m5B80DlZHAlxdt7" + "iZFe0pItl55DxBrnGvR4IbZmf6g4K96oLPubbacCgYEAiI3m1WDgzSWSc7ILa-qa" + "nc3C6t_2XX0bWdXycS62jPDwQbdUtmceksZ1MO-AdAxpTGS_jrvXwmMXdqG04WYD" + "blhtx7KHK_3dcXf4UNHS_1ojg27zMspUxGbXt4BqJGkOqehUHqjLPKjhVn80_y9k" + "_F3GqoCwkQPvSR4DASpnwdECgYEAnb5R4prPl3XA2Dx8KGYVUiXLPiul-97xo6MU" + "CCgSNKMkfJ56nw9_v1WhENHiP8S9SS7y5h1muZ59VCoXPkFy9bIEVW9l0GuZRTPo" + "0vS9KM_BBJmI7EwGyBvvnMPZ1Oi7f9_xvpk_ihHlDTZa7ENFyuaq4RRxmNIPaZhg" + "tyTtTeECgYEA2q4b3_saP_gNUVWZADzuY4YgbDsvhYxYvPboxB0HQULqr6-A63p_" + "QslCL1dPkqQXNjcon4gzIguwrfSFD1vFhKqR1WLfdJ6RIZNXn-YXaiqJ0DjbT5Fj" + "004n2BU6UABWLTf8L8OwkcvdFeWT2Yvz3fT38VDbQOdspyDODvtRP2Y", +}; + +static std::string pubs[NumTestRootKeys] = { + // Root 1 pub + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArSzp0Z8xFFs6f3SixM_i" + "Fni-HG5Gfdsfjm7fKNSnRHmC656oazWTpUgC0GCrzs8xYwIRoTyFbIQZAQf4cJpA" + "2EKVIkWxPslHuXUmCGRFGtoOp-m_YEgZ2T36NG0dbFOuzPDGLnUw2EwyZrPZqLPK" + "IwsWP6qHgI0FRWyR7FQoGfYqjjKsbS2Xt2oFkDt8121XKYrxLIWe3gYgUstwqCdz" + "T82rAtzpLvMVD74Rte5qHfb8XD2untlmmnpE9jMyhzYOdNqsUYuGTy3NBAJNg5Og" + "AVAINWrcoFJaSNjlBZuHYtk7414o2DSkbppI5mWil_l5u4rSYQWjIHWhzqd7cdJ6" + "bwIDAQAB", + + // Root 2 pub + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyZtxZnkBrmZzFF7GNA9X" + "YUFaBSl1MqcLEgqGW9PUyS48LK5r7PBXDCnF4e5u04VcKJ2PKPLHwRv9_ZGYQeeV" + "JYVoBIomEOISXXXHKf90PwYKswFqXILzB9AaYUvftgp2mubfVj94Eiq5GKvFwr7y" + "qY3Yqj6tSSWNi6eV-FJt4ypth4CIpyZPrrixnvI02gUOSF1Xwwk8PVgM2a_9FKWf" + "lFSYeN7p97ORkdXnA82XeYX9h2RHMomtZMCCtNpjWmioLgUXyQeS6Qq1Q2wfAPOZ" + "q-amHayq_Dxy5db9KbIe13AdbEv2BCoQlyL1fKSBQWiRGhkSxPwrKuseLp90j1xj" + "hQIDAQAB", + + // Root 3 pub + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwRy4kb2eXFXyTPVGewfB" + "bZVNoOoLOLKdqxLvnFl7-9jwWwS49GNZ8kpfO3nCU1qsoD198fLaTBvz9GVnsmrj" + "pxLuA8im8Rq8O56kNs2XUDqftCFGCCSBqbDww4vcHuTdeQF3xqzL2ezIe4hDqF3r" + "3Uu7VkzNmLhIccW03SEB7xDYH7tat_6nAE_CuToqQh3V8gTQulRckONhAGG3CK_5" + "DqHpk_GU8AFmWO8um2bPyTGW9pQGcQj5TieLpIWZmS6r8_NyF056B7b9PZ10Zozk" + "LTdUVvEy3dMeQXLVJBn3ZpccZB6M8UaD1UMW7HXEn0saro506cMWdx06g6EMRv3G" + "bwIDAQAB", +}; + +static std::string pubhashies[NumTestRootKeys] = { + // SHA256 of root 1 pub + "KHN0ZGluKT0gNzVmZWU5N2U1MGQxZjY4MWRmNTdmNWM1Njg4OWFhOGIyNjY1NDQ0" + "MDYyZTE3NzAxOTJlNzE5ZjMzMWM3ZjY0Ngo=", + + // SHA256 of root 2 pub + "KHN0ZGluKT0gOTBkYjJmZGM5Nzc2ODRjNjY4MmRkOWI2NmEyYzdjOGNhMzNiNWY5" + "YTA3OTE4YjQwMzBjMTJhMjA5M2RkYzJhOAo=", + + // SHA256 of root 3 pub + "KHN0ZGluKT0gNTJhNDRlMjVkODM3YzNjOGMzZWIwZTg0MWI3OWE0MzhjNGYzZDc0" + "NWIwMTRhMjE0MmNjMjc4NTFlODAxYzM0Ngo=", +}; + +static std::string modulus[NumTestRootKeys] = { + // Root 1 modulus + "00:ad:2c:e9:d1:9f:31:14:5b:3a:7f:74:a2:c4:cf:" + "e2:16:78:be:1c:6e:46:7d:db:1f:8e:6e:df:28:d4:" + "a7:44:79:82:eb:9e:a8:6b:35:93:a5:48:02:d0:60:" + "ab:ce:cf:31:63:02:11:a1:3c:85:6c:84:19:01:07:" + "f8:70:9a:40:d8:42:95:22:45:b1:3e:c9:47:b9:75:" + "26:08:64:45:1a:da:0e:a7:e9:bf:60:48:19:d9:3d:" + "fa:34:6d:1d:6c:53:ae:cc:f0:c6:2e:75:30:d8:4c:" + "32:66:b3:d9:a8:b3:ca:23:0b:16:3f:aa:87:80:8d:" + "05:45:6c:91:ec:54:28:19:f6:2a:8e:32:ac:6d:2d:" + "97:b7:6a:05:90:3b:7c:d7:6d:57:29:8a:f1:2c:85:" + "9e:de:06:20:52:cb:70:a8:27:73:4f:cd:ab:02:dc:" + "e9:2e:f3:15:0f:be:11:b5:ee:6a:1d:f6:fc:5c:3d:" + "ae:9e:d9:66:9a:7a:44:f6:33:32:87:36:0e:74:da:" + "ac:51:8b:86:4f:2d:cd:04:02:4d:83:93:a0:01:50:" + "08:35:6a:dc:a0:52:5a:48:d8:e5:05:9b:87:62:d9:" + "3b:e3:5e:28:d8:34:a4:6e:9a:48:e6:65:a2:97:f9:" + "79:bb:8a:d2:61:05:a3:20:75:a1:ce:a7:7b:71:d2:" + "7a:6f", + + // Root 2 modulus + "00:c9:9b:71:66:79:01:ae:66:73:14:5e:c6:34:0f:" + "57:61:41:5a:05:29:75:32:a7:0b:12:0a:86:5b:d3:" + "d4:c9:2e:3c:2c:ae:6b:ec:f0:57:0c:29:c5:e1:ee:" + "6e:d3:85:5c:28:9d:8f:28:f2:c7:c1:1b:fd:fd:91:" + "98:41:e7:95:25:85:68:04:8a:26:10:e2:12:5d:75:" + "c7:29:ff:74:3f:06:0a:b3:01:6a:5c:82:f3:07:d0:" + "1a:61:4b:df:b6:0a:76:9a:e6:df:56:3f:78:12:2a:" + "b9:18:ab:c5:c2:be:f2:a9:8d:d8:aa:3e:ad:49:25:" + "8d:8b:a7:95:f8:52:6d:e3:2a:6d:87:80:88:a7:26:" + "4f:ae:b8:b1:9e:f2:34:da:05:0e:48:5d:57:c3:09:" + "3c:3d:58:0c:d9:af:fd:14:a5:9f:94:54:98:78:de:" + "e9:f7:b3:91:91:d5:e7:03:cd:97:79:85:fd:87:64:" + "47:32:89:ad:64:c0:82:b4:da:63:5a:68:a8:2e:05:" + "17:c9:07:92:e9:0a:b5:43:6c:1f:00:f3:99:ab:e6:" + "a6:1d:ac:aa:fc:3c:72:e5:d6:fd:29:b2:1e:d7:70:" + "1d:6c:4b:f6:04:2a:10:97:22:f5:7c:a4:81:41:68:" + "91:1a:19:12:c4:fc:2b:2a:eb:1e:2e:9f:74:8f:5c:" + "63:85", + + // Root 3 modulus + "00:c1:1c:b8:91:bd:9e:5c:55:f2:4c:f5:46:7b:07:" + "c1:6d:95:4d:a0:ea:0b:38:b2:9d:ab:12:ef:9c:59:" + "7b:fb:d8:f0:5b:04:b8:f4:63:59:f2:4a:5f:3b:79:" + "c2:53:5a:ac:a0:3d:7d:f1:f2:da:4c:1b:f3:f4:65:" + "67:b2:6a:e3:a7:12:ee:03:c8:a6:f1:1a:bc:3b:9e:" + "a4:36:cd:97:50:3a:9f:b4:21:46:08:24:81:a9:b0:" + "f0:c3:8b:dc:1e:e4:dd:79:01:77:c6:ac:cb:d9:ec:" + "c8:7b:88:43:a8:5d:eb:dd:4b:bb:56:4c:cd:98:b8:" + "48:71:c5:b4:dd:21:01:ef:10:d8:1f:bb:5a:b7:fe:" + "a7:00:4f:c2:b9:3a:2a:42:1d:d5:f2:04:d0:ba:54:" + "5c:90:e3:61:00:61:b7:08:af:f9:0e:a1:e9:93:f1:" + "94:f0:01:66:58:ef:2e:9b:66:cf:c9:31:96:f6:94:" + "06:71:08:f9:4e:27:8b:a4:85:99:99:2e:ab:f3:f3:" + "72:17:4e:7a:07:b6:fd:3d:9d:74:66:8c:e4:2d:37:" + "54:56:f1:32:dd:d3:1e:41:72:d5:24:19:f7:66:97:" + "1c:64:1e:8c:f1:46:83:d5:43:16:ec:75:c4:9f:4b:" + "1a:ae:8e:74:e9:c3:16:77:1d:3a:83:a1:0c:46:fd:" + "c6:6f", +}; + +static size_t exponent[NumTestRootKeys] = { + 65537, // 0x10001 + 65537, // 0x10001 + 65537, // 0x10001 +}; + +static std::string siggies[NumTestRootKeys] = { + // protected signed with root1 + "UPLul7v7l2jTAGzrQDSQJZgTSk+ZzbskxXY8lHNGEYILmcMsgvB2MnRJis7NFFiH" + "QHyE4b6YdThgvgKLWwTLaLc7isQIluLMQt6AC3Dh0wHgplH+B80LwbHS83Tg1EiS" + "mdH2IkF2syFAT0UG/g2jqreLaiG79iAsNWI0+2/7bAvMOc/DCdYrjIuOVVtUEjOp" + "u0rxPiGPsFOC8M8YV8H23xF8l9sj4R82zkbYonvtrJZtQ/1xyhXdWdy/qVsjSUMI" + "TyuIuzCx8tJrKvYy5yLLI4N/xJs48KFoyKDEbMvL8saKO3oxTja1nTPI9UOfTRHa" + "zRorMmj/ACeDA21Ovws6VA", // removed 2 '=' from the end + + // protected signed with root2 + "qUtUfzf1k3QyIx70SObEB30b1LcIGu38kvFGEu5J9eTVcUgE+QSJ0R/LndIk/q1P" + "Bqlk3KjbqWQKn6HERYR4r+/vG8PmHb0VEzA9mC5IO/4so2NxiGbJSVTHrznEw4EG" + "D+Qb5L6RGcl5BBK2v3czWbi3Tv5+wu9v6Nzj1F4+ZYCYgMd4PJP0czfFN8//d2Zf" + "EarxekrjbIi3pQ3V8qE6Abo7r4nEU65nK8ksB2rfXOcPYHCaOdNM+m1viXhf4Bay" + "GG4HCLj8WqxLs/hFp196ki0GztKblvC9CnuPBk5YOnbmlT2j9I6FtXuzEhefQ0K3" + "rut4jR3k5CtdoachHCrLAw", // removed 2 '=' from the end + + // protected signed with root3 + "DEdx66Dcilyk+/S9RUdz2Ag+1wuMoChVDrNFM4+Lt5WlZJhdcpaWms3KbsMVG6V4" + "N7WFgMBdh8QLmqs8tirE4O4LEh1DR/V1/xJA41P3FQLk2wTpFGruDtcOxsaav36i" + "7psZ75FBudXHUaWBVeIIRRNU8/Fq0dTucSdvwW2ZQLjgWqJPP+9tIrrpHpzI1Jkd" + "JwImTU/k8anxAdZ/RB1TpCOA7F9REHQBBcvpn5wLo95x5iu5chSWoJP0zsZJgHZ+" + "J4sJTX26RKF3NZMznW4DDY1keguTKmaCElVblTTW1LGvOplG+a05/ivAj4ySYC9J" + "vQV+sDyuyQwfjBFn2j36MQ", // removed 2 '=' from the end +}; + +class TestRSAPrivateKey +{ + aduc::rootkeypkgtestutils::rootkeys m_rootkey; + +public: + TestRSAPrivateKey(aduc::rootkeypkgtestutils::rootkeys rootkey) : m_rootkey{ rootkey } + { + } + + ~TestRSAPrivateKey() + { + } + + TestRSAPrivateKey(const TestRSAPrivateKey&) = delete; + TestRSAPrivateKey& operator=(const TestRSAPrivateKey&) = delete; + TestRSAPrivateKey(TestRSAPrivateKey&&) = delete; + TestRSAPrivateKey& operator=(TestRSAPrivateKey&&) = delete; + + std::string SignData(const std::string& data) const + { + UNREFERENCED_PARAMETER(data); + // TODO: Use OpenSSL to actually create the signature using private key and data. + // For now, return hard-coded signatuers for now per root key. + auto index = static_cast::type>(m_rootkey); + return siggies[index]; + } +}; + +class TestRSAPublicKey +{ + aduc::rootkeypkgtestutils::rootkeys m_rootkey; + +public: + TestRSAPublicKey(aduc::rootkeypkgtestutils::rootkeys rootkey) : m_rootkey(rootkey) + { + } + + ~TestRSAPublicKey() + { + } + + TestRSAPublicKey(const TestRSAPublicKey&) = delete; + TestRSAPublicKey& operator=(const TestRSAPublicKey&) = delete; + TestRSAPublicKey(TestRSAPublicKey&&) = delete; + TestRSAPublicKey& operator=(TestRSAPublicKey&&) = delete; + + // returns hex-encoded with colon delimiter + std::string GetModulus() const + { + // TODO: Use OpenSSL to get the modulus from public key + // For now, return hard-coded ones per pre-canned root key. + auto index = static_cast::type>(m_rootkey); + return std::string{ modulus[index] }; + } + + size_t GetExponent() const + { + // TODO: Use OpenSSL to get the exponent from public key + // For now, return hard-coded ones per pre-canned root key. + auto index = static_cast::type>(m_rootkey); + return exponent[index]; + } + + // returns base64 of sha256 of pubkey + std::string getSha256HashOfPublicKey() const + { + // TODO: Calculate the hash of the dynamically-generated public key. + // For now, return hard-coded ones. + auto index = static_cast::type>(m_rootkey); + return pubhashies[index]; + } + + bool VerifySignature(const std::string& signature) const + { + // TODO: use OpenSSL to calculate signature + // For now, compare with hard-coded signatures + auto index = static_cast::type>(m_rootkey); + return siggies[index] == signature; + } +}; + +class TestRSAKeyPair +{ + TestRSAPrivateKey* privateKey; + TestRSAPublicKey* publicKey; + + aduc::rootkeypkgtestutils::rootkeys m_rootkey; + +public: + TestRSAKeyPair(aduc::rootkeypkgtestutils::rootkeys rootkey) : m_rootkey(rootkey) + { + // TODO: generate private/public key pairs. + // for now, rootkey is specified. + privateKey = new TestRSAPrivateKey{ rootkey }; + publicKey = new TestRSAPublicKey{ rootkey }; + } + + ~TestRSAKeyPair() + { + delete privateKey; + delete publicKey; + } + + TestRSAKeyPair(const TestRSAKeyPair&) = delete; + TestRSAKeyPair& operator=(const TestRSAKeyPair&) = delete; + TestRSAKeyPair(TestRSAKeyPair&&) = delete; + TestRSAKeyPair& operator=(TestRSAKeyPair&&) = delete; + + const TestRSAPublicKey& GetPublicKey() const + { + return *publicKey; + } + + const TestRSAPrivateKey& GetPrivateKey() const + { + return *privateKey; + } +}; + +} // namespace rootkeypkgtestutils +} // namespace aduc + +#endif // ROOTKEYPKGTESTUTILS_HPP diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/README.md b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/README.md new file mode 100644 index 000000000..2f76a18ec --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/README.md @@ -0,0 +1,29 @@ +# Test Data for rootkeypackage_utils + +## Root Key Package + +The root key package is rootkey.json file. + +## create_and_verify_signatures.sh + +create_and_verify_signatures.sh will: + +- Generate private and public keys, +- Create rootkey.data.json.testrootX.(base64 | binary).sig, +- and verify the signatures against rootkey.data.json data that was signed. + +## Key pairs + +Regenerate the key by doing: + +```bash +openssl genrsa 2048 | openssl base64 > testrootX.base64.txt +``` + +## Modulus and Exponent + +Get the RSA modulus and exponent by doing: + +```bash +openssl rsa -pubin -inform PEM -text -noout < pubX.pem +``` diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/create_and_verify_signatures.sh b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/create_and_verify_signatures.sh new file mode 100755 index 000000000..67f88665b --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/create_and_verify_signatures.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +# reconstitute the self-signed test private keys +base64 --decode ./testroot1.base64.txt > ./testroot1.pem +base64 --decode ./testroot2.base64.txt > ./testroot2.pem + +# get the public keys +openssl rsa -in testroot1.pem -pubout -out pub1.pem +openssl rsa -in testroot2.pem -pubout -out pub2.pem + +# write the raw binary signatures +openssl dgst -sign ./testroot1.pem -sha256 -binary ./rootkey.data.json > ./rootkey.data.json.testroot1.binary.sig +openssl dgst -sign ./testroot2.pem -sha256 -binary ./rootkey.data.json > ./rootkey.data.json.testroot2.binary.sig + +# write the Base64 URL encoded signatures +openssl dgst -sign ./testroot1.pem -sha256 -binary ./rootkey.data.json | openssl base64 | tr -- '+/=' '-_ ' > ./rootkey.data.json.testroot1.base64url.sig +openssl dgst -sign ./testroot2.pem -sha256 -binary ./rootkey.data.json | openssl base64 | tr -- '+/=' '-_ ' > ./rootkey.data.json.testroot2.base64url.sig + +# Verify the raw binary signatures against the data that was signed (rootkey.data.json) +openssl dgst -verify ./pub1.pem -sha256 -binary -signature ./rootkey.data.json.testroot1.binary.sig ./rootkey.data.json +openssl dgst -verify ./pub2.pem -sha256 -binary -signature ./rootkey.data.json.testroot2.binary.sig ./rootkey.data.json diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_1.base64url.txt b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_1.base64url.txt new file mode 100644 index 000000000..54cbea5ce --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_1.base64url.txt @@ -0,0 +1 @@ +AK0s6dGfMRRbOn90osTP4hZ4vhxuRn3bH45u3yjUp0R5guueqGs1k6VIAtBgq87PMWMCEaE8hWyEGQEH-HCaQNhClSJFsT7JR7l1JghkRRraDqfpv2BIGdk9-jRtHWxTrszwxi51MNhMMmaz2aizyiMLFj-qh4CNBUVskexUKBn2Ko4yrG0tl7dqBZA7fNdtVymK8SyFnt4GIFLLcKgnc0_NqwLc6S7zFQ--EbXuah32_Fw9rp7ZZpp6RPYzMoc2DnTarFGLhk8tzQQCTYOToAFQCDVq3KBSWkjY5QWbh2LZO-NeKNg0pG6aSOZlopf5ebuK0mEFoyB1oc6ne3HSem8 diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_2.base64url.txt b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_2.base64url.txt new file mode 100644 index 000000000..6059c3536 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/modulus_2.base64url.txt @@ -0,0 +1 @@ +AMmbcWZ5Aa5mcxRexjQPV2FBWgUpdTKnCxIKhlvT1MkuPCyua-zwVwwpxeHubtOFXCidjyjyx8Eb_f2RmEHnlSWFaASKJhDiEl11xyn_dD8GCrMBalyC8wfQGmFL37YKdprm31Y_eBIquRirxcK-8qmN2Ko-rUkljYunlfhSbeMqbYeAiKcmT664sZ7yNNoFDkhdV8MJPD1YDNmv_RSln5RUmHje6fezkZHV5wPNl3mF_YdkRzKJrWTAgrTaY1poqC4FF8kHkukKtUNsHwDzmavmph2sqvw8cuXW_SmyHtdwHWxL9gQqEJci9XykgUFokRoZEsT8KyrrHi6fdI9cY4U diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/root2.sig.base64.txt b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/root2.sig.base64.txt new file mode 100644 index 000000000..a98b6d54e --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/root2.sig.base64.txt @@ -0,0 +1,6 @@ +qUtUfzf1k3QyIx70SObEB30b1LcIGu38kvFGEu5J9eTVcUgE+QSJ0R/LndIk/q1P +Bqlk3KjbqWQKn6HERYR4r+/vG8PmHb0VEzA9mC5IO/4so2NxiGbJSVTHrznEw4EG +D+Qb5L6RGcl5BBK2v3czWbi3Tv5+wu9v6Nzj1F4+ZYCYgMd4PJP0czfFN8//d2Zf +EarxekrjbIi3pQ3V8qE6Abo7r4nEU65nK8ksB2rfXOcPYHCaOdNM+m1viXhf4Bay +GG4HCLj8WqxLs/hFp196ki0GztKblvC9CnuPBk5YOnbmlT2j9I6FtXuzEhefQ0K3 +rut4jR3k5CtdoachHCrLAw== diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.data.json b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.data.json new file mode 100644 index 000000000..4b6f3fa17 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.data.json @@ -0,0 +1 @@ +{"isTest":false,"version":1,"published":1667343602,"disabledRootKeys":["rootkey2"],"disabledSigningKeys":[{"alg":"SHA256","hash":"sVMpGd8aPo17piBBc-f1Bki0iCJPZmKvA43GG3SsG1E"}],"rootKeys":{"rootkey1":{"keyType":"RSA","n":"AK0s6dGfMRRbOn90osTP4hZ4vhxuRn3bH45u3yjUp0R5guueqGs1k6VIAtBgq87PMWMCEaE8hWyEGQEH-HCaQNhClSJFsT7JR7l1JghkRRraDqfpv2BIGdk9-jRtHWxTrszwxi51MNhMMmaz2aizyiMLFj-qh4CNBUVskexUKBn2Ko4yrG0tl7dqBZA7fNdtVymK8SyFnt4GIFLLcKgnc0_NqwLc6S7zFQ--EbXuah32_Fw9rp7ZZpp6RPYzMoc2DnTarFGLhk8tzQQCTYOToAFQCDVq3KBSWkjY5QWbh2LZO-NeKNg0pG6aSOZlopf5ebuK0mEFoyB1oc6ne3HSem8","e":65537},"rootkey2":{"keyType":"RSA","n":"AMmbcWZ5Aa5mcxRexjQPV2FBWgUpdTKnCxIKhlvT1MkuPCyua-zwVwwpxeHubtOFXCidjyjyx8Eb_f2RmEHnlSWFaASKJhDiEl11xyn_dD8GCrMBalyC8wfQGmFL37YKdprm31Y_eBIquRirxcK-8qmN2Ko-rUkljYunlfhSbeMqbYeAiKcmT664sZ7yNNoFDkhdV8MJPD1YDNmv_RSln5RUmHje6fezkZHV5wPNl3mF_YdkRzKJrWTAgrTaY1poqC4FF8kHkukKtUNsHwDzmavmph2sqvw8cuXW_SmyHtdwHWxL9gQqEJci9XykgUFokRoZEsT8KyrrHi6fdI9cY4U","e":65537}}} diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.json b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.json new file mode 100644 index 000000000..8e5bb28b5 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.json @@ -0,0 +1,38 @@ +{ + "protected": { + "isTest": false, + "version": 1, + "published": 1667343602, + "disabledRootKeys": [ + "rootkey2" + ], + "disabledSigningKeys": [ + { + "alg": "SHA256", + "hash": "sVMpGd8aPo17piBBc-f1Bki0iCJPZmKvA43GG3SsG1E" + } + ], + "rootKeys": { + "rootkey1": { + "keyType": "RSA", + "n": "AK0s6dGfMRRbOn90osTP4hZ4vhxuRn3bH45u3yjUp0R5guueqGs1k6VIAtBgq87PMWMCEaE8hWyEGQEH-HCaQNhClSJFsT7JR7l1JghkRRraDqfpv2BIGdk9-jRtHWxTrszwxi51MNhMMmaz2aizyiMLFj-qh4CNBUVskexUKBn2Ko4yrG0tl7dqBZA7fNdtVymK8SyFnt4GIFLLcKgnc0_NqwLc6S7zFQ--EbXuah32_Fw9rp7ZZpp6RPYzMoc2DnTarFGLhk8tzQQCTYOToAFQCDVq3KBSWkjY5QWbh2LZO-NeKNg0pG6aSOZlopf5ebuK0mEFoyB1oc6ne3HSem8", + "e": 65537 + }, + "rootkey2": { + "keyType": "RSA", + "n": "AMmbcWZ5Aa5mcxRexjQPV2FBWgUpdTKnCxIKhlvT1MkuPCyua-zwVwwpxeHubtOFXCidjyjyx8Eb_f2RmEHnlSWFaASKJhDiEl11xyn_dD8GCrMBalyC8wfQGmFL37YKdprm31Y_eBIquRirxcK-8qmN2Ko-rUkljYunlfhSbeMqbYeAiKcmT664sZ7yNNoFDkhdV8MJPD1YDNmv_RSln5RUmHje6fezkZHV5wPNl3mF_YdkRzKJrWTAgrTaY1poqC4FF8kHkukKtUNsHwDzmavmph2sqvw8cuXW_SmyHtdwHWxL9gQqEJci9XykgUFokRoZEsT8KyrrHi6fdI9cY4U", + "e": 65537 + } + } + }, + "signatures": [ + { + "alg": "RS256", + "sig": "aN94C4nO0mGAa35AR0sC_kUWBTRbT1hFTZgpBdHqE_AmjaP0Otzj2n_-kKTM_qGiNxhc7yfwV-TQanxOO4hFxgmhAIyLNlkDtjMGsSFG1c8aXxgEOctMrxaDvTXmWo45L_qmvOVHbwnzeUc0GcIvCwaA8y8aXiqEsb206yPJexT7gU2LxiGeUbJK8OobdjJPNPh4VF1WLUO9F0tkE2c4SkeqH9gAlJDZPum446NmFCsOCP2a9rCckd2KQOfeprvuYlQ9mdfIyZ59gleWWYBmES0q1lHkX05SnderYZ8cKxAqb8_9GheGM0wTSkrVjJh1Jva2kMY-tDs0bw-v-XL37Q" + }, + { + "alg": "RS256", + "sig": "UStcZ32TV8KmRheCOQO86U4LDG8cLu5qMgkbP-30-Cz4IXXKzM-bD7NadIh8BTAZ4R5bAHjf0UI_Gi5tSKyWdP9Wc_fZqAu-9ZKHbq503hyHQ486gMThP9EfZn3MuRXtiMwWQHeU8SKoq83IIgffZkHEoi-HGlQE7l4yLT62UiG2l2o6u3JBDapsjwWDrtTUrl3EgwnS-ecS5W7cOuuWHbEd8vp2vGulhYNUvsSzDi4gNdDXP7iKA5JZRlrmvIZ9z_Oz0n-CgP5FwG7-izDeyxI-ezYAnZyvUzNW0niDLOa1nIXCZalk-uH3Ag5gOAvlqyxbP2KmeH13GecLW-BCjw" + } + ] +} diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.base64.txt b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.base64.txt new file mode 100644 index 000000000..11c711d66 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.base64.txt @@ -0,0 +1,35 @@ +LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVB +clN6cDBaOHhGRnM2ZjNTaXhNL2lGbmkrSEc1R2Zkc2ZqbTdmS05TblJIbUM2NTZv +CmF6V1RwVWdDMEdDcnpzOHhZd0lSb1R5RmJJUVpBUWY0Y0pwQTJFS1ZJa1d4UHNs +SHVYVW1DR1JGR3RvT3ArbS8KWUVnWjJUMzZORzBkYkZPdXpQREdMblV3MkV3eVpy +UFpxTFBLSXdzV1A2cUhnSTBGUld5UjdGUW9HZllxampLcwpiUzJYdDJvRmtEdDgx +MjFYS1lyeExJV2UzZ1lnVXN0d3FDZHpUODJyQXR6cEx2TVZENzRSdGU1cUhmYjhY +RDJ1Cm50bG1tbnBFOWpNeWh6WU9kTnFzVVl1R1R5M05CQUpOZzVPZ0FWQUlOV3Jj +b0ZKYVNOamxCWnVIWXRrNzQxNG8KMkRTa2JwcEk1bVdpbC9sNXU0clNZUVdqSUhX +aHpxZDdjZEo2YndJREFRQUJBb0lCQUNJQW81aHBMWFhWdzlLcQowQnJjeG9PckNZ +a0RqZ3ZBTHA0RTN3UmhYTVp4SldlbUsyT0JqWS95WjdzS2dER0hOU2Mvakw2ZjU0 +SzdIVDI2Cmx1bGxJRDVXTkhvYVBRY2E5bDVQeGp2M2xDb0Zqc01oZmxZbFVnMzV3 +VnJ4NGNrWFZVY2dMNG1Ic1NPSE1vNC8KMmdqcDVGS2xKcVV4a3BHSEh2WFdyNEE3 +dGZRQ3N2OCtVZS90MXdRcEM2ZzFqN0swZDlNMy9MTjhCRjAzN2gyeApzV1lzWGE4 +MHpZOUNUL2tuSnRUWGJBTDJESTZ4Skg1Q0hYOEtDZjV0MmdHZHNzdmVLcVAyZEho +UjZQbEl0bFcvCm5xQnc4bEpvYmhwUEJFb29rZ2JTR2RUYm1zMk9EQmc1VHdPN0dG +dWRDWWIxRW5BeXZkamRIWHhKSmdNekM0aEwKMCtZaHZZRUNnWUVBMVdQZHZRZlJJ +U1NQckhVN3dwdzkrcitrS3NnTTNGOG9wNm5TZWpqdEQ4N21obmFPSXFscQpXazkw +ZE1MbHYwbCtwZnNsSVdZUW5SV0ZaSjNTSnpFZ3dWNnR1SFFxWlFzN0g4bi9yMDBz +WW54dk0xamFDaFI1ClBOVXA4K3hjWFdsVFFlelVPNUIwNTNXVzA0SFBTcCtoTE8y +bGljYkFESGJOK25idE9DRGdyNzhDZ1lFQXo4RlgKMnlONXhNSWUzaUkzV3BMMGxT +aVNnUmRZMmk5Y2tjWXVZSU44TTYrbEZCTUkxNlF3VWNuemZsZ2lzdG8rMGJ4bQpF +SlMwamRPOXVIelUwaXNzQXFPNHd0NmE5UFQ1U2dZL0FucUhweUdDMXpIRlNxOCtM +S25MR1dLcS8zVVhBMDdYCmMwU0dIMXNhd0lPU0dTaUxsaTZ1cFptOThYUVVFQ2kx +ellDODRWRUNnWUE3dmRYYWtsR3VZYm9Ib2xxMHhXRmsKempwNzc3NEtCR294Wm80 +U3dkVTgwOFFlYVJxcUFaeFE1R1hLT3JadnMzZk5xRjVnMTE1WFhDc1lYRWIxeWY5 +TgpvK0FtLy83T2d6SnVWL05KZE9XMFBQbzArZTh4VzBJR0VmZkkzcWVOVDJ1THpX +NHRydWZMMVZRQXF4c0ozVjhXCllRSXpiSDFmLy9MeTZGREpvZ3JGcVFLQmdRQ2xM +YW0yZDR3M0hjZ0JBTjlWeWdWZ0dqUHhJeWpud0VRdk9veGcKKytsaUJzS1BKVnNn +YUZCcWx0QmJvYU5rNUJTU0dPSmxTSFlOVlU1QVFpL0xNYnY2RlVXdTJlSUY1RWZY +elFPSAo2dmV6ci9jaE5WY1JQQ2VJeHk3TmJoOWFvRE85MDQrRSsvUlBOZFlkUGY2 +SXRpM1ZLQ1IvVWE4dExBZFBtYTZDClIxcmxJUUtCZ0FsWmd4TS9aaTUrY01zb1BH +c0d2elg1YS91MUpNQ2RtM0F1YzVRM0tVOUNFWlFnUHp2MlRhNzcKVzJiQkd2cHZp +VVlERXp6VFF2cWlvKytCakIzcGxzZ3dGWU9uV1ZMTVhCRWhDdzhJeWh5bXlyR2sx +Vm44L1YrdwpPRHRDSGZOWUpDdGR4TE4yUDNtL3lUZWNCYkdKTmJZRmg1M056Z2FC +bDc2U3NhdjBRRWs5Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.txt b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.txt new file mode 100644 index 000000000..1d6478e84 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot1.txt @@ -0,0 +1,25 @@ +MIIEowIBAAKCAQEArSzp0Z8xFFs6f3SixM_iFni-HG5Gfdsfjm7fKNSnRHmC656o +azWTpUgC0GCrzs8xYwIRoTyFbIQZAQf4cJpA2EKVIkWxPslHuXUmCGRFGtoOp-m_ +YEgZ2T36NG0dbFOuzPDGLnUw2EwyZrPZqLPKIwsWP6qHgI0FRWyR7FQoGfYqjjKs +bS2Xt2oFkDt8121XKYrxLIWe3gYgUstwqCdzT82rAtzpLvMVD74Rte5qHfb8XD2u +ntlmmnpE9jMyhzYOdNqsUYuGTy3NBAJNg5OgAVAINWrcoFJaSNjlBZuHYtk7414o +2DSkbppI5mWil_l5u4rSYQWjIHWhzqd7cdJ6bwIDAQABAoIBACIAo5hpLXXVw9Kq +0BrcxoOrCYkDjgvALp4E3wRhXMZxJWemK2OBjY_yZ7sKgDGHNSc_jL6f54K7HT26 +lullID5WNHoaPQca9l5Pxjv3lCoFjsMhflYlUg35wVrx4ckXVUcgL4mHsSOHMo4_ +2gjp5FKlJqUxkpGHHvXWr4A7tfQCsv8-Ue_t1wQpC6g1j7K0d9M3_LN8BF037h2x +sWYsXa80zY9CT_knJtTXbAL2DI6xJH5CHX8KCf5t2gGdssveKqP2dHhR6PlItlW_ +nqBw8lJobhpPBEookgbSGdTbms2ODBg5TwO7GFudCYb1EnAyvdjdHXxJJgMzC4hL +0-YhvYECgYEA1WPdvQfRISSPrHU7wpw9-r-kKsgM3F8op6nSejjtD87mhnaOIqlq +Wk90dMLlv0l-pfslIWYQnRWFZJ3SJzEgwV6tuHQqZQs7H8n_r00sYnxvM1jaChR5 +PNUp8-xcXWlTQezUO5B053WW04HPSp-hLO2licbADHbN-nbtOCDgr78CgYEAz8FX +2yN5xMIe3iI3WpL0lSiSgRdY2i9ckcYuYIN8M6-lFBMI16QwUcnzflgisto-0bxm +EJS0jdO9uHzU0issAqO4wt6a9PT5SgY_AnqHpyGC1zHFSq8-LKnLGWKq_3UXA07X +c0SGH1sawIOSGSiLli6upZm98XQUECi1zYC84VECgYA7vdXaklGuYboHolq0xWFk +zjp7774KBGoxZo4SwdU808QeaRqqAZxQ5GXKOrZvs3fNqF5g115XXCsYXEb1yf9N +o-Am__7OgzJuV_NJdOW0PPo0-e8xW0IGEffI3qeNT2uLzW4trufL1VQAqxsJ3V8W +YQIzbH1f__Ly6FDJogrFqQKBgQClLam2d4w3HcgBAN9VygVgGjPxIyjnwEQvOoxg +--liBsKPJVsgaFBqltBboaNk5BSSGOJlSHYNVU5AQi_LMbv6FUWu2eIF5EfXzQOH +6vezr_chNVcRPCeIxy7Nbh9aoDO904-E-_RPNdYdPf6Iti3VKCR_Ua8tLAdPma6C +R1rlIQKBgAlZgxM_Zi5-cMsoPGsGvzX5a_u1JMCdm3Auc5Q3KU9CEZQgPzv2Ta77 +W2bBGvpviUYDEzzTQvqio--BjB3plsgwFYOnWVLMXBEhCw8IyhymyrGk1Vn8_V-w +ODtCHfNYJCtdxLN2P3m_yTecBbGJNbYFh53NzgaBl76Ssav0QEk9 diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.base64.txt b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.base64.txt new file mode 100644 index 000000000..0b6959cf4 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.base64.txt @@ -0,0 +1,35 @@ +LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVB +eVp0eFpua0JybVp6RkY3R05BOVhZVUZhQlNsMU1xY0xFZ3FHVzlQVXlTNDhMSzVy +CjdQQlhEQ25GNGU1dTA0VmNLSjJQS1BMSHdSdjkvWkdZUWVlVkpZVm9CSW9tRU9J +U1hYWEhLZjkwUHdZS3N3RnEKWElMekI5QWFZVXZmdGdwMm11YmZWajk0RWlxNUdL +dkZ3cjd5cVkzWXFqNnRTU1dOaTZlVitGSnQ0eXB0aDRDSQpweVpQcnJpeG52STAy +Z1VPU0YxWHd3azhQVmdNMmEvOUZLV2ZsRlNZZU43cDk3T1JrZFhuQTgyWGVZWDlo +MlJICk1vbXRaTUNDdE5waldtaW9MZ1VYeVFlUzZRcTFRMndmQVBPWnErYW1IYXlx +L0R4eTVkYjlLYkllMTNBZGJFdjIKQkNvUWx5TDFmS1NCUVdpUkdoa1N4UHdyS3Vz +ZUxwOTBqMXhqaFFJREFRQUJBb0lCQVFDYjYwRDNyR3cxY2Z4YwphN1BFUFgwcHRU +NG1zZHAyOHlPbnIwWWNMS2JyZEh1TFh0WVBLQTFhVmRBNW5JcFB3bHIwK20zbWtH +VVduMHgrCjJDUTJEQ0dZSkNXL0pReXRqL24rR0FHUkpJVEYzU2xYS2FnVnBoekpG +UlBoM2FsRmc3QVl1cWROYjhhdjNpVEsKeE1Zc2lEcnFFTTdaVTZIMjZUa2dJZHJs +Y3ZLVGRUUTIzYzMrbUFXWWpmay9SeXNOQUNDU2UycnRyakdORlJZbQpTZ3QwdVhW +bi94SldIaU1QR0svTnJQZWExVGx1TjVZMFFYelYxTFBFS2xNRzFjMStzOUYzME1B +NGNDM1FmSG90CnI5NmNEODNZSlJqV2ovOFU3VHlNY3FOYWhSUWk4TDBxQklLTTVJ +UnEzQm1nV3NHUmdZdHFjYmJTb0kwckFoMkUKNkZsTExSNGRBb0dCQU9uSUZFYkM4 +bEorUytoZ1p6aEdaVW5Jcm9JN3R2eFZyMVVCenhMSk5FMGxhVkRhTGJuagp5bUNN +dCtvM2R3VVEzZ3g2YUlsRVUvNlNUUHE1WVVkRXFjLzVMSjFyU09VQzNqTC9RSUhP +R0tGcExCdmljcDh1CmFxVy9RWjJHdDJsOStoYTVDbkF3ME5aRGhCNSt5eHg4N2dJ +MVRRY0tTNytVcEFLNmxVL2p5NjVyQW9HQkFOekUKanpoQjdQdmVOSUErWjRuV01W +cW1xa1FlMlk4N1FHN2FLbVZGMk1neURmRVdxKzNVaTNnaUs2ZFBMaHZNYmZUTQpt +T2I3V1dPWjR3cTNiZlN6aHFZQTEyZ3oyZmo1MkdPd0djc1hNZTliT2JHc3Y5dmVB +QzQxWkRtblh4Q0d4d2tWCjNwYjhkalV4Y0daM3JYNFBnMDU3RzdzakRBWE9NWnU5 +RUplVUQ5SFBBb0dCQU9Pei9wUGhvNWJYN3VWNnFHNzIKbWdkZzBTQ0dPemZSMllI +SnprQjArMTA4MkRScEhlcVdSWEwrL00vRGtFaTk0aGx6VE1pT1plVnA2Rks1SjFm +OApPQTRhbStzRUtTN3VPVENnejlyZXU3elRyS1BJVDI1ZURvQThKaFBodUZtbTIy +VXdmRXRFTU5UUlZDbER4RitPCkMyRFpPNXBrMjl6UlVXSmJDNzJSbWJ6YkFvR0JB +SjhSamJSV1pCL3lzbGQ1SDNkRWV4azdIMUduL05Ca08vL2oKZUVxeU1nbkZieUE0 +V3JjcHZ6aFhQcWIxdVY1VVJTSHV6WGtZd0FheEdkTmQ2WDg0WDV0NjNicDZLZU5v +ZWs4UgowdlB2aVk1U1o5YXFoeTh2M1dkdUZ3SW5vNnF2d2ZlODV6NVpOLzhKMlZn +cmdUbGtpaExoUjFEbVpzSkVHS0NECmNOSVczL01uQW9HQWZUSUZpYU9FbzloaEli +MFJKUWM5WlhoY1l3WnE5dXVTNEJsaGhMck9PR0dKbEFEd0ptZzUKSmVTTnQwVGpL +VEcwQU9Kd3UvTyt1SGtwRXJza2FnQmRud2RmMDhXdHJMc3hXcS8vMFdZQWdsYnJa +MTJnb0c0LwoyaVhvQTlyUzRiUTB5YnhRTVU5bkxDNnJIcTRrdE5OYmNWNjFoamRS +Rzk0cnJJUm9uNnBodWgwPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= diff --git a/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.txt b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.txt new file mode 100644 index 000000000..3b6ffd0a7 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/testroot2.txt @@ -0,0 +1,25 @@ +MIIEpQIBAAKCAQEAyZtxZnkBrmZzFF7GNA9XYUFaBSl1MqcLEgqGW9PUyS48LK5r +7PBXDCnF4e5u04VcKJ2PKPLHwRv9_ZGYQeeVJYVoBIomEOISXXXHKf90PwYKswFq +XILzB9AaYUvftgp2mubfVj94Eiq5GKvFwr7yqY3Yqj6tSSWNi6eV-FJt4ypth4CI +pyZPrrixnvI02gUOSF1Xwwk8PVgM2a_9FKWflFSYeN7p97ORkdXnA82XeYX9h2RH +MomtZMCCtNpjWmioLgUXyQeS6Qq1Q2wfAPOZq-amHayq_Dxy5db9KbIe13AdbEv2 +BCoQlyL1fKSBQWiRGhkSxPwrKuseLp90j1xjhQIDAQABAoIBAQCb60D3rGw1cfxc +a7PEPX0ptT4msdp28yOnr0YcLKbrdHuLXtYPKA1aVdA5nIpPwlr0-m3mkGUWn0x- +2CQ2DCGYJCW_JQytj_n-GAGRJITF3SlXKagVphzJFRPh3alFg7AYuqdNb8av3iTK +xMYsiDrqEM7ZU6H26TkgIdrlcvKTdTQ23c3-mAWYjfk_RysNACCSe2rtrjGNFRYm +Sgt0uXVn_xJWHiMPGK_NrPea1TluN5Y0QXzV1LPEKlMG1c1-s9F30MA4cC3QfHot +r96cD83YJRjWj_8U7TyMcqNahRQi8L0qBIKM5IRq3BmgWsGRgYtqcbbSoI0rAh2E +6FlLLR4dAoGBAOnIFEbC8lJ-S-hgZzhGZUnIroI7tvxVr1UBzxLJNE0laVDaLbnj +ymCMt-o3dwUQ3gx6aIlEU_6STPq5YUdEqc_5LJ1rSOUC3jL_QIHOGKFpLBvicp8u +aqW_QZ2Gt2l9-ha5CnAw0NZDhB5-yxx87gI1TQcKS7-UpAK6lU_jy65rAoGBANzE +jzhB7PveNIA-Z4nWMVqmqkQe2Y87QG7aKmVF2MgyDfEWq-3Ui3giK6dPLhvMbfTM +mOb7WWOZ4wq3bfSzhqYA12gz2fj52GOwGcsXMe9bObGsv9veAC41ZDmnXxCGxwkV +3pb8djUxcGZ3rX4Pg057G7sjDAXOMZu9EJeUD9HPAoGBAOOz_pPho5bX7uV6qG72 +mgdg0SCGOzfR2YHJzkB0-1082DRpHeqWRXL-_M_DkEi94hlzTMiOZeVp6FK5J1f8 +OA4am-sEKS7uOTCgz9reu7zTrKPIT25eDoA8JhPhuFmm22UwfEtEMNTRVClDxF-O +C2DZO5pk29zRUWJbC72RmbzbAoGBAJ8RjbRWZB_ysld5H3dEexk7H1Gn_NBkO__j +eEqyMgnFbyA4WrcpvzhXPqb1uV5URSHuzXkYwAaxGdNd6X84X5t63bp6KeNoek8R +0vPviY5SZ9aqhy8v3WduFwIno6qvwfe85z5ZN_8J2VgrgTlkihLhR1DmZsJEGKCD +cNIW3_MnAoGAfTIFiaOEo9hhIb0RJQc9ZXhcYwZq9uuS4BlhhLrOOGGJlADwJmg5 +JeSNt0TjKTG0AOJwu_O-uHkpErskagBdnwdf08WtrLsxWq__0WYAglbrZ12goG4_ +2iXoA9rS4bQ0ybxQMU9nLC6rHq4ktNNbcV61hjdRG94rrIRon6phuh0 diff --git a/src/utils/rootkeypackage_utils/tests/src/main.cpp b/src/utils/rootkeypackage_utils/tests/src/main.cpp new file mode 100644 index 000000000..ed920b3ed --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/src/main.cpp @@ -0,0 +1,9 @@ +/** + * @file main.cpp + * @brief rootkeypackage_utils tests main entry point. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#define CATCH_CONFIG_MAIN +#include diff --git a/src/utils/rootkeypackage_utils/tests/src/rootkeypackage_download_ut.cpp b/src/utils/rootkeypackage_utils/tests/src/rootkeypackage_download_ut.cpp new file mode 100644 index 000000000..4a0e50103 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/src/rootkeypackage_download_ut.cpp @@ -0,0 +1,95 @@ +/** + * @file rootkeypackage_utils_ut.cpp + * @brief Unit Tests for rootkeypackage_utils library + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include +#include +#include +#include +#include +#include +#include + +using Catch::Matchers::Equals; + +class TestCaseFixture +{ +public: + TestCaseFixture() : m_testPath{ ADUC_SystemUtils_GetTemporaryPathName() } + { + m_testPath += "/rootkeypackage_download_ut"; + + (void)ADUC_SystemUtils_RmDirRecursive(m_testPath.c_str()); + (void)ADUC_SystemUtils_MkDirRecursiveDefault(m_testPath.c_str()); + } + + ~TestCaseFixture() + { + (void)ADUC_SystemUtils_RmDirRecursive(m_testPath.c_str()); + } + + const char* TestPath() const + { + return m_testPath.c_str(); + } + + TestCaseFixture(const TestCaseFixture&) = delete; + TestCaseFixture& operator=(const TestCaseFixture&) = delete; + TestCaseFixture(TestCaseFixture&&) = delete; + TestCaseFixture& operator=(TestCaseFixture&&) = delete; + + static ADUC_Result TestRootKeyPkgDownload(const char* rootKeyPkgUrl, const char* targetFilePath) + { + ADUC_Result result{ ADUC_GeneralResult_Failure, 0 }; + try + { + std::ofstream ofs; + ofs.open(targetFilePath); + REQUIRE((ofs.rdstate() & std::ofstream::badbit) == 0); + ofs << "rootKeyPkgUrl=" << rootKeyPkgUrl << ", targetFilePath=" << targetFilePath; + ofs.close(); + + result.ResultCode = ADUC_GeneralResult_Success; + } + catch (...) + { + } + + return result; + } + +private: + std::string m_testPath{}; +}; + +TEST_CASE_METHOD(TestCaseFixture, "RootKeyPackageUtils_DownloadPackage") +{ + ADUC_RootKeyPkgDownloaderInfo downloaderInfo{ + /* .name = */ "test-downloader", + /* .downloadFn = */ TestCaseFixture::TestRootKeyPkgDownload, + /* .downloadBaseDir = */ TestPath(), + }; + + const std::string rootKeyPkgUrl{ "http://localhost:8080/path/fake.json" }; + const std::string workflowId{ "afc5140e-b253-4f37-a810-d9593bd7fc0c" }; + STRING_HANDLE downloadedFile = nullptr; + ADUC_Result result{ ADUC_RootKeyPackageUtils_DownloadPackage( + "http://localhost:8080/path/fake.json", workflowId.c_str(), &downloaderInfo, &downloadedFile) }; + + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + + std::stringstream ssExpectedDownloadFile{}; + ssExpectedDownloadFile << TestPath() << "/" << workflowId << "/fake.json"; + const std::string expectedDownloadFilePath{ ssExpectedDownloadFile.str() }; + CHECK_THAT(STRING_c_str(downloadedFile), Equals(expectedDownloadFilePath)); + + std::stringstream ssExpectedContent{}; + ssExpectedContent << "rootKeyPkgUrl=" << rootKeyPkgUrl << ", targetFilePath=" << expectedDownloadFilePath; + const std::string expectedDownloadContent{ ssExpectedContent.str() }; + CHECK_THAT( + aduc::FileTestUtils_slurpFile(std::string(STRING_c_str(downloadedFile))), Equals(expectedDownloadContent)); +} diff --git a/src/utils/rootkeypackage_utils/tests/src/rootkeypackage_utils_ut.cpp b/src/utils/rootkeypackage_utils/tests/src/rootkeypackage_utils_ut.cpp new file mode 100644 index 000000000..c10823f66 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/src/rootkeypackage_utils_ut.cpp @@ -0,0 +1,390 @@ +/** + * @file rootkeypackage_utils_ut.cpp + * @brief Unit Tests for rootkeypackage_utils library + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "rootkeypkgtestutils.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Catch::Matchers::Equals; + +static std::string get_rootkey_package_template_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/rootkeypackage_utils/rootkeypackage_template.json"; + return path; +} + +static std::string get_example_rootkey_package_json_path() +{ + std::string path{ ADUC_TEST_DATA_FOLDER }; + path += "/rootkeypackage_utils/rootkeypackage.json"; + return path; +} + +static std::string get_serialized_protectedProperties(JSON_Value* rootkeyPkgJsonValue) +{ + JSON_Object* pkgJsonObj = json_object(rootkeyPkgJsonValue); + REQUIRE(pkgJsonObj != nullptr); + + JSON_Object* protectedProperties = json_object_get_object(pkgJsonObj, "protected"); + REQUIRE(protectedProperties != nullptr); + + char* serializedProtectedProperties_cstr = + json_serialize_to_string(json_object_get_wrapping_value(protectedProperties)); + REQUIRE(serializedProtectedProperties_cstr != nullptr); + + std::string protectedPropertiesSerialized = serializedProtectedProperties_cstr; + + json_free_serialized_string(serializedProtectedProperties_cstr); + serializedProtectedProperties_cstr = nullptr; + + return protectedPropertiesSerialized; +} + +static std::string fillout_protected_properties_template_params( + const std::string& templateStr, + const char* disabledHashPublicSigningKey, + const char* modulus_1, + size_t exponent_1, + const char* modulus_2, + size_t exponent_2, + const char* modulus_3, + size_t exponent_3) +{ + std::string str = aduc::FileTestUtils_applyTemplateParam( + templateStr, "disabledHashPublicSigningKey", disabledHashPublicSigningKey); + + auto conv = [](size_t exp) { + std::stringstream ss; + ss << exp; + return ss.str(); + }; + std::string exp1_str = conv(exponent_1); + std::string exp2_str = conv(exponent_2); + std::string exp3_str = conv(exponent_3); + + str = aduc::FileTestUtils_applyTemplateParam(str, "modulus_1", modulus_1); + str = aduc::FileTestUtils_applyTemplateParam(str, "exponent_1", exp1_str.c_str()); + + str = aduc::FileTestUtils_applyTemplateParam(str, "modulus_2", modulus_2); + str = aduc::FileTestUtils_applyTemplateParam(str, "exponent_2", exp2_str.c_str()); + + str = aduc::FileTestUtils_applyTemplateParam(str, "modulus_3", modulus_3); + str = aduc::FileTestUtils_applyTemplateParam(str, "exponent_3", exp3_str.c_str()); + + return str; +} + +static std::string convert_hexcolon_to_URLUIntBase64String(const std::string& hexcolon) +{ + std::stringstream ss{ hexcolon }; + std::vector hexBytes; + while (ss.good()) + { + std::string tok; + getline(ss, tok, ':'); + hexBytes.push_back(tok); + } + + auto hex2nibble = [](char c) { + if (c >= '0' && c <= '9') + { + return c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + return c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') + { + return c - 'A' + 10; + } + throw std::invalid_argument("bad hex char"); + }; + + std::vector bytes; + for (const std::string& hexByte : hexBytes) + { + uint8_t hi_nibble = (uint8_t)hex2nibble(hexByte[0]); + uint8_t lo_nibble = (uint8_t)hex2nibble(hexByte[1]); + uint8_t byte = (hi_nibble << 4) | lo_nibble; + bytes.push_back(byte); + } + + char* encoded = Base64URLEncode(bytes.data(), bytes.size()); + std::string base64url{ encoded }; + free(encoded); + return base64url; +} +static std::string get_valid_rootkey_package( + const char* disabledHashPublicSigningKey, + const char* modulus_1, + size_t exponent_1, + const char* modulus_2, + size_t exponent_2, + const char* modulus_3, + size_t exponent_3, + const aduc::rootkeypkgtestutils::TestRSAPrivateKey& rootkey1_privateKey, + const aduc::rootkeypkgtestutils::TestRSAPrivateKey& rootkey2_privateKey, + const aduc::rootkeypkgtestutils::TestRSAPrivateKey& rootkey3_privateKey) +{ + std::string json_template = aduc::FileTestUtils_slurpFile(get_rootkey_package_template_json_path().c_str()); + REQUIRE(json_template.length() > 0); + + // Fill out the "protected" properties template parameters, but do not fill out + // the signatures "sig" properties yet. + std::string templateStr = fillout_protected_properties_template_params( + json_template, + disabledHashPublicSigningKey, + modulus_1, + exponent_1, + modulus_2, + exponent_2, + modulus_3, + exponent_3); + + // Generate the signatures using the rootkey private keys passed in + // and the protected properties data to be signed. + JSON_Value* pkgJsonValue = json_parse_string(templateStr.c_str()); + REQUIRE(pkgJsonValue != nullptr); + + std::string protectedProperties = get_serialized_protectedProperties(pkgJsonValue); + + std::string rootkeysig_1 = rootkey1_privateKey.SignData(protectedProperties); + std::string rootkeysig_2 = rootkey2_privateKey.SignData(protectedProperties); + std::string rootkeysig_3 = rootkey3_privateKey.SignData(protectedProperties); + + templateStr = aduc::FileTestUtils_applyTemplateParam(templateStr, "rootkeysig_1", rootkeysig_1.c_str()); + templateStr = aduc::FileTestUtils_applyTemplateParam(templateStr, "rootkeysig_2", rootkeysig_2.c_str()); + templateStr = aduc::FileTestUtils_applyTemplateParam(templateStr, "rootkeysig_3", rootkeysig_3.c_str()); + + json_value_free(pkgJsonValue); + return templateStr; +} + +TEST_CASE("RootKeyPackageUtils_Parse") +{ + SECTION("bad json") + { + ADUC_Result result = { ADUC_GeneralResult_Failure, 0 }; + + ADUC_RootKeyPackage pkg{}; + + result = ADUC_RootKeyPackageUtils_Parse(nullptr, &pkg); + REQUIRE(IsAducResultCodeFailure(result.ResultCode)); + CHECK(result.ExtendedResultCode == ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG); + + result = ADUC_RootKeyPackageUtils_Parse("", &pkg); + REQUIRE(IsAducResultCodeFailure(result.ResultCode)); + CHECK(result.ExtendedResultCode == ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_ARG); + + result = ADUC_RootKeyPackageUtils_Parse("{[}", &pkg); + REQUIRE(IsAducResultCodeFailure(result.ResultCode)); + CHECK(result.ExtendedResultCode == ADUC_ERC_UTILITIES_ROOTKEYPKG_UTIL_ERROR_BAD_JSON); + } + + SECTION("valid template") + { + aduc::rootkeypkgtestutils::TestRSAKeyPair rootKeyPair1{ aduc::rootkeypkgtestutils::rootkeys::rootkey1 }; + aduc::rootkeypkgtestutils::TestRSAKeyPair rootKeyPair2{ aduc::rootkeypkgtestutils::rootkeys::rootkey2 }; + aduc::rootkeypkgtestutils::TestRSAKeyPair rootKeyPair3{ aduc::rootkeypkgtestutils::rootkeys::rootkey3 }; + + const auto& rootkey1_publickey = rootKeyPair1.GetPublicKey(); + const auto& rootkey2_publickey = rootKeyPair2.GetPublicKey(); + const auto& rootkey3_publickey = rootKeyPair3.GetPublicKey(); + + std::string urlIntBase64EncodedHash_of_rootkey3_public_key = rootkey3_publickey.getSha256HashOfPublicKey(); + const char* PUBLIC_SIGNING_KEY_CHAINING_UP_TO_ROOTKEY_3 = + urlIntBase64EncodedHash_of_rootkey3_public_key.c_str(); + + std::string ROOTKEY_1_MODULUS = convert_hexcolon_to_URLUIntBase64String(rootkey1_publickey.GetModulus()); + size_t ROOTKEY_1_EXPONENT = rootkey1_publickey.GetExponent(); + + std::string ROOTKEY_2_MODULUS = convert_hexcolon_to_URLUIntBase64String(rootkey2_publickey.GetModulus()); + size_t ROOTKEY_2_EXPONENT = rootkey2_publickey.GetExponent(); + + std::string ROOTKEY_3_MODULUS = convert_hexcolon_to_URLUIntBase64String(rootkey3_publickey.GetModulus()); + size_t ROOTKEY_3_EXPONENT = rootkey3_publickey.GetExponent(); + + const std::string rootKeyPkgJsonStr = get_valid_rootkey_package( + PUBLIC_SIGNING_KEY_CHAINING_UP_TO_ROOTKEY_3, // disabledHashPublicSigningKey + ROOTKEY_1_MODULUS.c_str(), // modulus_1 + ROOTKEY_1_EXPONENT, // exponent_1 + ROOTKEY_2_MODULUS.c_str(), // modulus_2 + ROOTKEY_2_EXPONENT, // exponent_2 + ROOTKEY_3_MODULUS.c_str(), // modulus_3 + ROOTKEY_3_EXPONENT, // exponent_3 + rootKeyPair1.GetPrivateKey(), // privateKey_1 + rootKeyPair2.GetPrivateKey(), // privateKey_2 + rootKeyPair3.GetPrivateKey() // privateKey_3 + ); + + ADUC_RootKeyPackage pkg{}; + ADUC_Result result = ADUC_RootKeyPackageUtils_Parse(rootKeyPkgJsonStr.c_str(), &pkg); + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + + // + // Verify "protected" properties + // + + // verify "version" and "published" + CHECK(pkg.protectedProperties.isTest == true); + CHECK(pkg.protectedProperties.version == 2); + CHECK(pkg.protectedProperties.publishedTime == 1667343602); + + REQUIRE(VECTOR_size(pkg.protectedProperties.disabledRootKeys) == 2); + + // verify "disabledRootKeys" + { + // put the KIDs from disabledRootKeys into std::vector for making it more convenient to do assertions. + const STRING_HANDLE* const disabledRootKey1 = + static_cast(VECTOR_element(pkg.protectedProperties.disabledRootKeys, 0)); + const STRING_HANDLE* const disabledRootKey2 = + static_cast(VECTOR_element(pkg.protectedProperties.disabledRootKeys, 1)); + + CHECK_THAT(STRING_c_str(*disabledRootKey1), Equals("rootkey1")); + CHECK_THAT(STRING_c_str(*disabledRootKey2), Equals("rootkey2")); + } + + // verify "disabledSigningKeys" + REQUIRE(VECTOR_size(pkg.protectedProperties.disabledSigningKeys) == 1); + { + void* el = VECTOR_element(pkg.protectedProperties.disabledSigningKeys, 0); + REQUIRE(el != nullptr); + + auto a = static_cast(el); + ADUC_RootKeyPackage_Hash signingKeyHash{ *a }; + CHECK(signingKeyHash.alg == SHA256); + + const CONSTBUFFER* hashBuffer = CONSTBUFFER_GetContent(signingKeyHash.hash); + REQUIRE(hashBuffer != nullptr); + + char* encodedHash = Base64URLEncode(hashBuffer->buffer, hashBuffer->size); + std::string encodedHashStr{ encodedHash }; + encodedHashStr = std::regex_replace(encodedHashStr, std::regex("="), ""); + + std::string expected{ PUBLIC_SIGNING_KEY_CHAINING_UP_TO_ROOTKEY_3 }; + expected = std::regex_replace(expected, std::regex("="), ""); + + CHECK(encodedHashStr == expected); + + CONSTBUFFER_DecRef(signingKeyHash.hash); + free(encodedHash); + } + + // verify "rootKeys" + REQUIRE(VECTOR_size(pkg.protectedProperties.rootKeys) == 3); + const ADUC_RootKey* const rootkey1 = + static_cast(VECTOR_element(pkg.protectedProperties.rootKeys, 0)); + const ADUC_RootKey* const rootkey2 = + static_cast(VECTOR_element(pkg.protectedProperties.rootKeys, 1)); + const ADUC_RootKey* const rootkey3 = + static_cast(VECTOR_element(pkg.protectedProperties.rootKeys, 2)); + + REQUIRE(rootkey1 != nullptr); + REQUIRE(rootkey2 != nullptr); + REQUIRE(rootkey3 != nullptr); + + CHECK_THAT(STRING_c_str(rootkey1->kid), Equals("rootkey1")); + CHECK_THAT(STRING_c_str(rootkey2->kid), Equals("rootkey2")); + CHECK_THAT(STRING_c_str(rootkey3->kid), Equals("rootkey3")); + + CHECK(rootkey1->keyType == ADUC_RootKey_KeyType_RSA); + CHECK(rootkey2->keyType == ADUC_RootKey_KeyType_RSA); + CHECK(rootkey3->keyType == ADUC_RootKey_KeyType_RSA); + + auto VerifyRsaParams = [](const ADUC_RSA_RootKeyParameters& rsaParams, + const std::string& expected_modulus, + size_t expected_exponent) { + CHECK(rsaParams.e == expected_exponent); + + const CONSTBUFFER* actual_modulus_buf = CONSTBUFFER_GetContent(rsaParams.n); + REQUIRE(actual_modulus_buf != nullptr); + + char* actual_modulus = Base64URLEncode(actual_modulus_buf->buffer, actual_modulus_buf->size); + REQUIRE(actual_modulus != nullptr); + + CHECK_THAT(actual_modulus, Equals(expected_modulus)); + free(actual_modulus); + }; + + VerifyRsaParams(rootkey1->rsaParameters, ROOTKEY_1_MODULUS, ROOTKEY_1_EXPONENT); + VerifyRsaParams(rootkey2->rsaParameters, ROOTKEY_2_MODULUS, ROOTKEY_2_EXPONENT); + VerifyRsaParams(rootkey3->rsaParameters, ROOTKEY_3_MODULUS, ROOTKEY_3_EXPONENT); + + // + // Verify "protected" properties tring + // + JSON_Value* pkgJson = json_parse_string(rootKeyPkgJsonStr.c_str()); + + REQUIRE(pkgJson != NULL); + + std::string protectedProperties = get_serialized_protectedProperties(pkgJson); + + CHECK_THAT(STRING_c_str(pkg.protectedPropertiesJsonString), Equals(protectedProperties.c_str())); + + json_value_free(pkgJson); + + // + // Verify "signatures" properties + // + REQUIRE(pkg.signatures != nullptr); + REQUIRE(VECTOR_size(pkg.signatures) == 3); + + auto verifyPkgSig = [&](size_t sig_index, const aduc::rootkeypkgtestutils::TestRSAKeyPair& testRootKeyPair) { + void* el = VECTOR_element(pkg.signatures, sig_index); + REQUIRE(el != nullptr); + + ADUC_RootKeyPackage_Signature* sig = static_cast(el); + REQUIRE(sig != nullptr); + + CHECK(sig->alg == ADUC_RootKeySigningAlgorithm_RS256); + + const CONSTBUFFER* signatureBuffer = CONSTBUFFER_GetContent(sig->signature); + REQUIRE(signatureBuffer != nullptr); + + char* encodedHash = Base64URLEncode(signatureBuffer->buffer, signatureBuffer->size); + std::string urlDecodedStr{ encodedHash }; + urlDecodedStr = std::regex_replace(urlDecodedStr, std::regex("_"), "/"); + urlDecodedStr = std::regex_replace(urlDecodedStr, std::regex("-"), "+"); + CHECK(testRootKeyPair.GetPublicKey().VerifySignature(urlDecodedStr)); + + free(encodedHash); + }; + + verifyPkgSig(0, rootKeyPair1); + verifyPkgSig(1, rootKeyPair2); + verifyPkgSig(2, rootKeyPair3); + + // + // Cleanup + // + ADUC_RootKeyPackageUtils_Destroy(&pkg); + } + + SECTION("valid example") + { + std::string rootkey_pkg_json = aduc::FileTestUtils_slurpFile(get_example_rootkey_package_json_path()); + + ADUC_RootKeyPackage pkg{}; + ADUC_Result result = ADUC_RootKeyPackageUtils_Parse(rootkey_pkg_json.c_str(), &pkg); + REQUIRE(IsAducResultCodeSuccess(result.ResultCode)); + + CHECK_FALSE(pkg.protectedProperties.isTest); + } +} diff --git a/src/utils/rootkeypackage_utils/tests/testapp/CMakeLists.txt b/src/utils/rootkeypackage_utils/tests/testapp/CMakeLists.txt new file mode 100644 index 000000000..cc143addb --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/testapp/CMakeLists.txt @@ -0,0 +1,12 @@ +set (target_name rootkeypackage_test_app) + +include (agentRules) + +compileasc99 () +disablertti () + +add_executable (${target_name}) +target_sources (${target_name} PRIVATE src/main.cpp) + +target_link_aziotsharedutil (${target_name} INTERFACE) +target_link_libraries (${target_name} PRIVATE aduc::rootkeypackage_utils aduc::test_utils) diff --git a/src/utils/rootkeypackage_utils/tests/testapp/README.md b/src/utils/rootkeypackage_utils/tests/testapp/README.md new file mode 100644 index 000000000..e43d139d9 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/testapp/README.md @@ -0,0 +1,23 @@ + +# rootkeypackage test app + +## Setup and run python http server + +- Ensure deliveryoptimization-agent is installed and running +- Ensure `adu` user is in `do` group and `do` user is in `do` and `adu` groups +- Run following steps: + +```sh +sudo rm -rf /tmp/deviceupdate/rootkey_download_test_app +mkdir /tmp/htdocs +cp src/utils/rootkeypackage_utils/tests/scripts/rootkeypkg/rootkeyfiles/rootkey.json /tmp/htdocs/ +pushd /tmp/htdocs +python3 -m http.server 8083 & +popd +``` + +## Run as adu user + +```sh +sudo -u adu ./out/bin/rootkeypackage_test_app +``` diff --git a/src/utils/rootkeypackage_utils/tests/testapp/src/main.cpp b/src/utils/rootkeypackage_utils/tests/testapp/src/main.cpp new file mode 100644 index 000000000..21f74302f --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/testapp/src/main.cpp @@ -0,0 +1,69 @@ +/** + * @file main.cpp + * @brief The main entrypoint for the rootkeypackage test app. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ +#include +#include +#include +#include +#include +#include + +#define ROOTKEY_PKG_URL "http://localhost:8083/rootkey.json" +#define WORKFLOW_ID "7cf7241f-9ede-3e37-ca72-a7593bd7fc0f" + +int main(int argc, char** argv) +{ + UNREFERENCED_PARAMETER(argc); // kept for posterity and it's a main() function + UNREFERENCED_PARAMETER(argv); + + ADUC_Result result = { 0, 0 }; + int ret = 1; + STRING_HANDLE downloadedFile = nullptr; + + std::string jsonString; + std::string filepathStr; + ADUC_RootKeyPackage rootKeyPackage{}; + + ADUC_RootKeyPkgDownloaderInfo downloaderInfo{ + "DO", + DownloadRootKeyPkg_DO, + "/tmp/deviceupdate/rootkey_download_test_app", + }; + + result = ADUC_RootKeyPackageUtils_DownloadPackage(ROOTKEY_PKG_URL, WORKFLOW_ID, &downloaderInfo, &downloadedFile); + + if (IsAducResultCodeFailure(result.ResultCode)) + { + printf("Download failed with erc 0x%08x.\n", result.ExtendedResultCode); + ret = 1; + goto done; + } + + printf("Downloaded file to %s\n", STRING_c_str(downloadedFile)); + + filepathStr = STRING_c_str(downloadedFile); + jsonString = aduc::FileTestUtils_slurpFile(filepathStr); + + printf("Parsing root key package at %s ...\n", STRING_c_str(downloadedFile)); + + result = ADUC_RootKeyPackageUtils_Parse(jsonString.c_str(), &rootKeyPackage); + + if (IsAducResultCodeFailure(result.ResultCode)) + { + printf("Failed parse of root key package, erc 0x%08x.\n", result.ExtendedResultCode); + ret = 1; + goto done; + } + + printf("Success!\n"); + ret = 0; + +done: + STRING_delete(downloadedFile); + + return ret; +} diff --git a/src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage.json b/src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage.json new file mode 100644 index 000000000..8e5bb28b5 --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage.json @@ -0,0 +1,38 @@ +{ + "protected": { + "isTest": false, + "version": 1, + "published": 1667343602, + "disabledRootKeys": [ + "rootkey2" + ], + "disabledSigningKeys": [ + { + "alg": "SHA256", + "hash": "sVMpGd8aPo17piBBc-f1Bki0iCJPZmKvA43GG3SsG1E" + } + ], + "rootKeys": { + "rootkey1": { + "keyType": "RSA", + "n": "AK0s6dGfMRRbOn90osTP4hZ4vhxuRn3bH45u3yjUp0R5guueqGs1k6VIAtBgq87PMWMCEaE8hWyEGQEH-HCaQNhClSJFsT7JR7l1JghkRRraDqfpv2BIGdk9-jRtHWxTrszwxi51MNhMMmaz2aizyiMLFj-qh4CNBUVskexUKBn2Ko4yrG0tl7dqBZA7fNdtVymK8SyFnt4GIFLLcKgnc0_NqwLc6S7zFQ--EbXuah32_Fw9rp7ZZpp6RPYzMoc2DnTarFGLhk8tzQQCTYOToAFQCDVq3KBSWkjY5QWbh2LZO-NeKNg0pG6aSOZlopf5ebuK0mEFoyB1oc6ne3HSem8", + "e": 65537 + }, + "rootkey2": { + "keyType": "RSA", + "n": "AMmbcWZ5Aa5mcxRexjQPV2FBWgUpdTKnCxIKhlvT1MkuPCyua-zwVwwpxeHubtOFXCidjyjyx8Eb_f2RmEHnlSWFaASKJhDiEl11xyn_dD8GCrMBalyC8wfQGmFL37YKdprm31Y_eBIquRirxcK-8qmN2Ko-rUkljYunlfhSbeMqbYeAiKcmT664sZ7yNNoFDkhdV8MJPD1YDNmv_RSln5RUmHje6fezkZHV5wPNl3mF_YdkRzKJrWTAgrTaY1poqC4FF8kHkukKtUNsHwDzmavmph2sqvw8cuXW_SmyHtdwHWxL9gQqEJci9XykgUFokRoZEsT8KyrrHi6fdI9cY4U", + "e": 65537 + } + } + }, + "signatures": [ + { + "alg": "RS256", + "sig": "aN94C4nO0mGAa35AR0sC_kUWBTRbT1hFTZgpBdHqE_AmjaP0Otzj2n_-kKTM_qGiNxhc7yfwV-TQanxOO4hFxgmhAIyLNlkDtjMGsSFG1c8aXxgEOctMrxaDvTXmWo45L_qmvOVHbwnzeUc0GcIvCwaA8y8aXiqEsb206yPJexT7gU2LxiGeUbJK8OobdjJPNPh4VF1WLUO9F0tkE2c4SkeqH9gAlJDZPum446NmFCsOCP2a9rCckd2KQOfeprvuYlQ9mdfIyZ59gleWWYBmES0q1lHkX05SnderYZ8cKxAqb8_9GheGM0wTSkrVjJh1Jva2kMY-tDs0bw-v-XL37Q" + }, + { + "alg": "RS256", + "sig": "UStcZ32TV8KmRheCOQO86U4LDG8cLu5qMgkbP-30-Cz4IXXKzM-bD7NadIh8BTAZ4R5bAHjf0UI_Gi5tSKyWdP9Wc_fZqAu-9ZKHbq503hyHQ486gMThP9EfZn3MuRXtiMwWQHeU8SKoq83IIgffZkHEoi-HGlQE7l4yLT62UiG2l2o6u3JBDapsjwWDrtTUrl3EgwnS-ecS5W7cOuuWHbEd8vp2vGulhYNUvsSzDi4gNdDXP7iKA5JZRlrmvIZ9z_Oz0n-CgP5FwG7-izDeyxI-ezYAnZyvUzNW0niDLOa1nIXCZalk-uH3Ag5gOAvlqyxbP2KmeH13GecLW-BCjw" + } + ] +} diff --git a/src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage_template.json b/src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage_template.json new file mode 100644 index 000000000..d7617f07f --- /dev/null +++ b/src/utils/rootkeypackage_utils/tests/testdata/rootkeypackage_utils/rootkeypackage_template.json @@ -0,0 +1,45 @@ +{ + "protected": { + "isTest": true, + "version": 2, + "published": 1667343602, + "disabledRootKeys": ["rootkey1", "rootkey2"], + "disabledSigningKeys": [ + { + "alg": "SHA256", + "hash": "{{disabledHashPublicSigningKey}}" + } + ], + "rootKeys": { + "rootkey1": { + "keyType": "RSA", + "n": "{{modulus_1}}", + "e": {{exponent_1}} + }, + "rootkey2": { + "keyType": "RSA", + "n": "{{modulus_2}}", + "e": {{exponent_2}} + }, + "rootkey3": { + "keyType": "RSA", + "n": "{{modulus_3}}", + "e": {{exponent_3}} + } + } + }, + "signatures": [ + { + "alg": "RS256", + "sig": "{{rootkeysig_1}}" + }, + { + "alg": "RS256", + "sig": "{{rootkeysig_2}}" + }, + { + "alg": "RS256", + "sig": "{{rootkeysig_3}}" + } + ] +} diff --git a/src/utils/system_utils/inc/aduc/system_utils.h b/src/utils/system_utils/inc/aduc/system_utils.h index 71438d569..7dc7e4f99 100644 --- a/src/utils/system_utils/inc/aduc/system_utils.h +++ b/src/utils/system_utils/inc/aduc/system_utils.h @@ -45,6 +45,8 @@ int ADUC_SystemUtils_MkSandboxDirRecursive(const char* path); int ADUC_SystemUtils_MkDirRecursiveAduUser(const char* path); +bool ADUC_SystemUtils_Exists(const char* path); + int ADUC_SystemUtils_RmDirRecursive(const char* path); int ADUC_SystemUtils_CopyFileToDir(const char* filePath, const char* dirPath, bool overwriteExistingFile); diff --git a/src/utils/system_utils/src/system_utils.c b/src/utils/system_utils/src/system_utils.c index d363a20af..a864586d9 100644 --- a/src/utils/system_utils/src/system_utils.c +++ b/src/utils/system_utils/src/system_utils.c @@ -199,6 +199,31 @@ int ADUC_SystemUtils_MkDirRecursiveDefault(const char* path) path, (uid_t)-1 /*userId*/, (gid_t)-1 /*groupId*/, (mode_t)S_IRWXU | S_IRWXG /*mode*/); } +/** + * @brief Checks if the file or directory at @p path exists + * + * @param path the path to the directory or file + * @return true if path exists, false otherwise + */ +bool ADUC_SystemUtils_Exists(const char* path) +{ + if (path == NULL) + { + return false; + } + + int result = 0; + struct stat buff; + + result = stat(path,&buff); + + if (result != 0) + { + return false; + } + + return true; +} /** * @brief Create a directory tree. * @@ -532,7 +557,20 @@ int ADUC_SystemUtils_CopyFileToDir(const char* filePath, const char* dirPath, co } /** - * @brief Writes @p buff to file at @p path using + * @brief Removes the file when caller knows the path refers to a file + * @remark On POSIX systems, it will remove a link to the name so it might not delete right away if there are other links + * or another process has it open. + * + * @param path The path to the file. + * @return int On success, 0 is returned. On error -1 is returned, and errno is set appropriately. + */ +int ADUC_SystemUtils_RemoveFile(const char* path) +{ + return unlink(path); +} + +/** + * @brief Writes @p buff to file at @p path * @details This function overwrites the current data in @p path with @p buff * * @param path the path to the file to write data diff --git a/src/utils/test_utils/inc/aduc/file_test_utils.hpp b/src/utils/test_utils/inc/aduc/file_test_utils.hpp index 839976aa7..4265651b3 100644 --- a/src/utils/test_utils/inc/aduc/file_test_utils.hpp +++ b/src/utils/test_utils/inc/aduc/file_test_utils.hpp @@ -16,6 +16,9 @@ namespace aduc { std::string FileTestUtils_slurpFile(const std::string& path); +std::string FileTestUtils_applyTemplateParam( + const std::string& templateStr, const char* parameterName, const char* parameterValue); + } // namespace aduc #endif // FILE_TEST_UTILS_HPP diff --git a/src/utils/test_utils/src/file_test_utils.cpp b/src/utils/test_utils/src/file_test_utils.cpp index 452239a4d..1f6ff37e1 100644 --- a/src/utils/test_utils/src/file_test_utils.cpp +++ b/src/utils/test_utils/src/file_test_utils.cpp @@ -9,6 +9,7 @@ #include "aduc/file_test_utils.hpp" #include +#include #include namespace aduc @@ -21,4 +22,13 @@ std::string FileTestUtils_slurpFile(const std::string& path) return buffer.str(); } +std::string +FileTestUtils_applyTemplateParam(const std::string& templateStr, const char* parameterName, const char* parameterValue) +{ + std::stringstream ss; + ss << "\\{\\{" << parameterName << "\\}\\}"; + std::string placeholder{ ss.str() }; + return std::regex_replace(templateStr, std::regex(placeholder.c_str()), parameterValue); +} + } // namespace aduc diff --git a/src/utils/url_utils/CMakeLists.txt b/src/utils/url_utils/CMakeLists.txt new file mode 100644 index 000000000..c3fc810e0 --- /dev/null +++ b/src/utils/url_utils/CMakeLists.txt @@ -0,0 +1,17 @@ +set (target_name url_utils) + +add_library (${target_name} STATIC) +add_library (aduc::${target_name} ALIAS ${target_name}) + +target_link_aziotsharedutil (${target_name} PUBLIC) + +target_sources (${target_name} PRIVATE src/https_proxy_utils.c src/url_utils.c) +target_include_directories (${target_name} PUBLIC inc ${ADUC_EXPORT_INCLUDES}) +target_link_libraries ( + ${target_name} + PUBLIC aduc::c_utils + PRIVATE aduc::logging) + +if (ADUC_BUILD_UNIT_TESTS) + add_subdirectory (tests) +endif () diff --git a/src/utils/https_proxy_utils/inc/aduc/https_proxy_utils.h b/src/utils/url_utils/inc/aduc/https_proxy_utils.h similarity index 100% rename from src/utils/https_proxy_utils/inc/aduc/https_proxy_utils.h rename to src/utils/url_utils/inc/aduc/https_proxy_utils.h diff --git a/src/utils/url_utils/inc/aduc/url_utils.h b/src/utils/url_utils/inc/aduc/url_utils.h new file mode 100644 index 000000000..64221cfb7 --- /dev/null +++ b/src/utils/url_utils/inc/aduc/url_utils.h @@ -0,0 +1,22 @@ +/** + * @file url_utils.h + * @brief Utilities for working with urls. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#ifndef ADUC_URL_UTILS_H +#define ADUC_URL_UTILS_H + +#include "aduc/c_utils.h" +#include "aduc/result.h" +#include "azure_c_shared_utility/strings.h" + +EXTERN_C_BEGIN + +ADUC_Result ADUC_UrlUtils_GetPathFileName(const char* url, STRING_HANDLE* outFileName); + +EXTERN_C_END + +#endif // ADUC_URL_UTILS_H diff --git a/src/utils/https_proxy_utils/src/https_proxy_utils.c b/src/utils/url_utils/src/https_proxy_utils.c similarity index 100% rename from src/utils/https_proxy_utils/src/https_proxy_utils.c rename to src/utils/url_utils/src/https_proxy_utils.c diff --git a/src/utils/url_utils/src/url_utils.c b/src/utils/url_utils/src/url_utils.c new file mode 100644 index 000000000..c41ff5ee3 --- /dev/null +++ b/src/utils/url_utils/src/url_utils.c @@ -0,0 +1,99 @@ +/** + * @file url_utils.c + * @brief Implements the url utils. + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include "aduc/url_utils.h" +#include "aduc/http_url.h" +#include "aduc/string_c_utils.h" +#include + +/** + * @brief Gets the filename at the end of URL path, or NULL if no such filename. + * @param[in] url The URL. + * @param[out] outFileName The out parameter to hold the filename string, or NULL. + * + * @returns ADUC_Result The result. On success, contents of outFileName will be + * the allocated STRING_HANDLE for the filename, or NULL if no trailing path segment. + * + * @details If no filename at the end, then result will be a failure and + * ExtendedResultCode will be ADUC_ERC_UTILITIES_URL_BAD_PATH for e.g. + * http://example.com/ or http://example.com + * + * If there is a query string, it will not include it. e.g. + * http://example.com/foo/bar?a=b will result in outFileName of bar. + */ +ADUC_Result ADUC_UrlUtils_GetPathFileName(const char* url, STRING_HANDLE* outFileName) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + const char *p = NULL, *q = NULL; + char* filename = NULL; + size_t filename_len = 0; + + if (IsNullOrEmpty(url) || outFileName == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_URL_BAD_ARG; + return result; + } + + p = strstr(url, "://"); + if (p == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_URL_BAD_URL; + goto done; + } + + p += 2; // Advance to the last fwd slash + + q = strrchr(url, '/'); + if (p == q) + { + // No slash after scheme separator so there's no file path + result.ExtendedResultCode = ADUC_ERC_UTILITIES_URL_BAD_PATH; + goto done; + } + + p = q + 1; // p is one past the right-most path separator + + while (*q != '\0' && *q != '?' && *q != '#') + { + q++; + } + + filename_len = (size_t)(q - p); + + if (filename_len == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_URL_BAD_PATH; + goto done; + } + + filename = malloc(filename_len + 1); + if (filename == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + + memcpy(filename, p, filename_len); + filename[filename_len] = '\0'; + + // Transfer ownership of memory to the STRING_HANDLE + *outFileName = STRING_new_with_memory(filename); + filename = NULL; + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + + if (IsAducResultCodeFailure(result.ResultCode)) + { + *outFileName = NULL; + } + + return result; +} diff --git a/src/utils/url_utils/tests/CMakeLists.txt b/src/utils/url_utils/tests/CMakeLists.txt new file mode 100644 index 000000000..861d5b2d5 --- /dev/null +++ b/src/utils/url_utils/tests/CMakeLists.txt @@ -0,0 +1,20 @@ +set (target_name url_utils_unit_test) + +project (url_utils_unit_test) + +include (agentRules) + +compileasc99 () +disablertti () + +find_package (Catch2 REQUIRED) + +add_executable (${target_name}) +target_sources (${target_name} PRIVATE main.cpp https_proxy_utils_ut.cpp url_utils_ut.cpp) + +target_link_libraries (${target_name} PRIVATE aduc::url_utils Catch2::Catch2) +target_link_libraries (${target_name} PRIVATE libaducpal) + +include (CTest) +include (Catch) +catch_discover_tests (${target_name}) diff --git a/src/utils/https_proxy_utils/tests/https_proxy_utils_ut.cpp b/src/utils/url_utils/tests/https_proxy_utils_ut.cpp similarity index 100% rename from src/utils/https_proxy_utils/tests/https_proxy_utils_ut.cpp rename to src/utils/url_utils/tests/https_proxy_utils_ut.cpp diff --git a/src/utils/https_proxy_utils/tests/main.cpp b/src/utils/url_utils/tests/main.cpp similarity index 79% rename from src/utils/https_proxy_utils/tests/main.cpp rename to src/utils/url_utils/tests/main.cpp index 3d2638049..e42e1d3a2 100644 --- a/src/utils/https_proxy_utils/tests/main.cpp +++ b/src/utils/url_utils/tests/main.cpp @@ -1,6 +1,6 @@ /** * @file main.cpp - * @brief c_utils tests main entry point. + * @brief url_utils tests main entry point. * * @copyright Copyright (c) Microsoft Corporation. * Licensed under the MIT License. diff --git a/src/utils/url_utils/tests/url_utils_ut.cpp b/src/utils/url_utils/tests/url_utils_ut.cpp new file mode 100644 index 000000000..de1f97b91 --- /dev/null +++ b/src/utils/url_utils/tests/url_utils_ut.cpp @@ -0,0 +1,68 @@ +/** + * @file url_utils_ut.cpp + * @brief Unit Tests for url_utils library + * + * @copyright Copyright (c) Microsoft Corporation. + * Licensed under the MIT License. + */ + +#include + +#include +using Catch::Matchers::Equals; + +TEST_CASE("ADUC_UrlUtils_GetPathFileName - non empty file and intermediate path segments") +{ + STRING_HANDLE urlPathFileName = nullptr; + REQUIRE(IsAducResultCodeSuccess( + ADUC_UrlUtils_GetPathFileName("http://somehost.com/path/to/file-v1.1.json", &urlPathFileName).ResultCode)); + CHECK_THAT(STRING_c_str(urlPathFileName), Equals("file-v1.1.json")); + STRING_delete(urlPathFileName); +} + +TEST_CASE("ADUC_UrlUtils_GetPathFileName - non empty file and no intermediate path segments") +{ + STRING_HANDLE urlPathFileName = nullptr; + REQUIRE(IsAducResultCodeSuccess( + ADUC_UrlUtils_GetPathFileName("http://somehost.com/file-v1.1.json", &urlPathFileName).ResultCode)); + CHECK_THAT(STRING_c_str(urlPathFileName), Equals("file-v1.1.json")); + STRING_delete(urlPathFileName); +} + +TEST_CASE("ADUC_UrlUtils_GetPathFileName - empty file") +{ + STRING_HANDLE urlPathFileName = nullptr; + ADUC_Result result = ADUC_UrlUtils_GetPathFileName("http://somehost.com/", &urlPathFileName); + REQUIRE(IsAducResultCodeFailure(result.ResultCode)); + CHECK(urlPathFileName == nullptr); + STRING_delete(urlPathFileName); +} + +TEST_CASE("ADUC_UrlUtils_GetPathFileName - empty file, no trailing slash") +{ + STRING_HANDLE urlPathFileName = nullptr; + ADUC_Result result = ADUC_UrlUtils_GetPathFileName("http://somehost.com", &urlPathFileName); + REQUIRE(IsAducResultCodeFailure(result.ResultCode)); + CHECK(urlPathFileName == nullptr); + STRING_delete(urlPathFileName); +} + +TEST_CASE("ADUC_UrlUtils_GetPathFileName - non empty file with query string") +{ + STRING_HANDLE urlPathFileName = nullptr; + REQUIRE(IsAducResultCodeSuccess( + ADUC_UrlUtils_GetPathFileName("http://somehost.com/path/to/file-v1.1.json?a=1&b=2", &urlPathFileName) + .ResultCode)); + CHECK_THAT(STRING_c_str(urlPathFileName), Equals("file-v1.1.json")); + STRING_delete(urlPathFileName); +} + +TEST_CASE("ADUC_UrlUtils_GetPathFileName - non empty file with query string and octothorpe anchor") +{ + STRING_HANDLE urlPathFileName = nullptr; + REQUIRE(IsAducResultCodeSuccess( + ADUC_UrlUtils_GetPathFileName("http://somehost.com/path/to/file-v1.1.json#anchor", &urlPathFileName) + .ResultCode)); + CHECK_THAT(STRING_c_str(urlPathFileName), Equals("file-v1.1.json")); + STRING_delete(urlPathFileName); +} diff --git a/src/utils/workflow_data_utils/inc/aduc/workflow_data_utils.h b/src/utils/workflow_data_utils/inc/aduc/workflow_data_utils.h index 2a982b46a..a6f4a1d15 100644 --- a/src/utils/workflow_data_utils/inc/aduc/workflow_data_utils.h +++ b/src/utils/workflow_data_utils/inc/aduc/workflow_data_utils.h @@ -86,6 +86,13 @@ char* ADUC_WorkflowData_GetUpdateType(const ADUC_WorkflowData* workflowData); */ char* ADUC_WorkflowData_GetInstalledCriteria(const ADUC_WorkflowData* workflowData); +/** + * @brief Creates a Workflow for the WorkflowHandle of the workflow data. + * + * @param workflowData The workflow data for which WorkflowHandle will be initialized. + */ +bool ADUC_WorkflowData_InitWorkflowHandle(ADUC_WorkflowData* workflowData); + EXTERN_C_END #endif // ADUC_DATA_WORKFLOW_UTILS_H diff --git a/src/utils/workflow_data_utils/src/workflow_data_utils.c b/src/utils/workflow_data_utils/src/workflow_data_utils.c index 0e2c703de..36af4cc2d 100644 --- a/src/utils/workflow_data_utils/src/workflow_data_utils.c +++ b/src/utils/workflow_data_utils/src/workflow_data_utils.c @@ -123,4 +123,16 @@ char* ADUC_WorkflowData_GetInstalledCriteria(const ADUC_WorkflowData* workflowDa return workflow_get_installed_criteria(workflowData->WorkflowHandle); } +/** + * @brief Creates a Workflow for the WorkflowHandle of the workflow data. + * + * @param workflowData The workflow data for which WorkflowHandle will be initialized. + * + * @returns true on success. + */ +bool ADUC_WorkflowData_InitWorkflowHandle(ADUC_WorkflowData* workflowData) +{ + return workflow_init_workflow_handle(workflowData); +} + EXTERN_C_END diff --git a/src/utils/workflow_utils/CMakeLists.txt b/src/utils/workflow_utils/CMakeLists.txt index c49f89970..50e105d08 100644 --- a/src/utils/workflow_utils/CMakeLists.txt +++ b/src/utils/workflow_utils/CMakeLists.txt @@ -25,7 +25,7 @@ target_compile_definitions ( PRIVATE SUPPORTED_UPDATE_MANIFEST_VERSION_MIN=${SUPPORTED_UPDATE_MANIFEST_VERSION_MIN} SUPPORTED_UPDATE_MANIFEST_VERSION_MAX=${SUPPORTED_UPDATE_MANIFEST_VERSION_MAX}) -target_link_aziotsharedutil (${target_name} PRIVATE) +target_link_aziotsharedutil (${target_name} PUBLIC) target_link_libraries ( ${target_name} @@ -36,8 +36,9 @@ target_link_libraries ( aduc::hash_utils aduc::logging aduc::parser_utils + aduc::reporting_utils + aduc::root_key_utils aduc::system_utils - aduc::workflow_utils aduc::jws_utils Parson::parson) diff --git a/src/utils/workflow_utils/inc/aduc/workflow_internal.h b/src/utils/workflow_utils/inc/aduc/workflow_internal.h index 0844da64b..44fea620e 100644 --- a/src/utils/workflow_utils/inc/aduc/workflow_internal.h +++ b/src/utils/workflow_utils/inc/aduc/workflow_internal.h @@ -13,6 +13,7 @@ #include #include #include +#include #include /** @@ -36,7 +37,7 @@ typedef struct tagADUC_Workflow ADUCITF_State State; /**< The current state machine state of the workflow. */ ADUCITF_WorkflowStep CurrentWorkflowStep; /**< The current state machine workflow step. */ ADUC_Result Result; /**< The result of the workflow. */ - ADUC_Result_t ResultSuccessErc; /**< The ERC to set on workflow success. */ + VECTOR_HANDLE ResultExtraExtendedResultCodes; /**< The extra ERCs. */ STRING_HANDLE ResultDetails; /**< The result details of the workflow. */ STRING_HANDLE InstalledUpdateId; /**< The installed updateId to report on workflow success. */ diff --git a/src/utils/workflow_utils/inc/aduc/workflow_utils.h b/src/utils/workflow_utils/inc/aduc/workflow_utils.h index f0e482169..017bd420b 100644 --- a/src/utils/workflow_utils/inc/aduc/workflow_utils.h +++ b/src/utils/workflow_utils/inc/aduc/workflow_utils.h @@ -449,8 +449,9 @@ ADUCITF_State workflow_get_state(ADUC_WorkflowHandle handle); ADUC_Result workflow_get_result(ADUC_WorkflowHandle handle); void workflow_set_result(ADUC_WorkflowHandle handle, ADUC_Result result); -ADUC_Result_t workflow_get_success_erc(ADUC_WorkflowHandle handle); -void workflow_set_success_erc(ADUC_WorkflowHandle handle, ADUC_Result_t erc); + +void workflow_add_erc(ADUC_WorkflowHandle handle, ADUC_Result_t erc); +STRING_HANDLE workflow_get_extra_ercs(ADUC_WorkflowHandle handle); /** * @brief Set workflow resultDetails string. @@ -755,6 +756,40 @@ bool workflow_get_force_update(ADUC_WorkflowHandle workflowHandle); */ void workflow_set_force_update(ADUC_WorkflowHandle handle, bool forceUpdate); +/** + * @brief peeks at the properties under the "workflow" unprotected property + * + * @param updateActionJsonObj The JSON object of the update action JSON. + * @param outWorkflowUpdateAction The output parameter for receiving the value of "action" under "workflow". May be set to NULL if there was none in the JSON. + * @param outRootKeyPkgUrl_optional The output parameter for receiving the value of "rootkeyPkgUrl" unprotected property from the updateAction json. Will not be set when error result is returned or NULL is passed. + * @param outWorkflowId_optional The output parameter for receiving the value of "id" under "workflow". May be set to NULL if there was none in the JSON. + * + * @details Caller must never free workflowId. + * @returns ADUC_Result The result. + */ +ADUC_Result workflow_parse_peek_unprotected_workflow_properties( + JSON_Object* updateActionJsonObj, + ADUCITF_UpdateAction* outWorkflowUpdateAction, + char** outRootkeyPkgUrl_optional, + char** outWorkflowId_optional); + +/** + * @brief Allocate and initialize a workflow handle onto the workflow Data. + * + * @param workflowData The workflow data on which to set the new workflow handle. + * @return true on success. + */ +bool workflow_init_workflow_handle(ADUC_WorkflowData* workflowData); + +/** + * @brief Sets the update action json on the workflow handle + * + * @param handle The workflow handle on which to set the update action json object. + * @param jsonObj The update action json object. + * @return true on success. + */ +bool workflow_set_update_action_object(ADUC_WorkflowHandle handle, JSON_Object* jsonObj); + EXTERN_C_END #endif // ADUC_WORKFLOW_UTILS_H diff --git a/src/utils/workflow_utils/src/workflow_utils.c b/src/utils/workflow_utils/src/workflow_utils.c index 8c8cb72a2..f7fa53621 100644 --- a/src/utils/workflow_utils/src/workflow_utils.c +++ b/src/utils/workflow_utils/src/workflow_utils.c @@ -9,21 +9,23 @@ #include "aduc/adu_types.h" #include "aduc/aduc_inode.h" // ADUC_INODE_SENTINEL_VALUE #include "aduc/config_utils.h" +#include "aduc/c_utils.h" #include "aduc/extension_manager.h" #include "aduc/hash_utils.h" #include "aduc/logging.h" #include "aduc/parser_utils.h" +#include "aduc/reporting_utils.h" #include "aduc/result.h" #include "aduc/string_c_utils.h" #include "aduc/system_utils.h" #include "aduc/types/update_content.h" #include "aduc/types/workflow.h" #include "aduc/workflow_internal.h" +#include "azure_c_shared_utility/crt_abstractions.h" // for mallocAndStrcpy_s +#include "azure_c_shared_utility/strings.h" // for STRING_* #include "jws_utils.h" -#include +#include "root_key_util.h" -#include // for mallocAndStrcpy_s -#include // for STRING_* #include #include // for va_* #include // for malloc, atoi @@ -58,6 +60,7 @@ #define STEP_PROPERTY_FIELD_HANDLER_PROPERTIES "handlerProperties" #define WORKFLOW_CHILDREN_BLOCK_SIZE 10 +#define WORKFLOW_MAX_SUCCESS_ERC 8 /** * @brief Maximum length for the 'resultDetails' string. @@ -702,27 +705,121 @@ const char* _workflow_get_properties_retryTimestamp(ADUC_WorkflowHandle handle) } /** - * @brief Helper function for checking the hash of the update manifest is equal to the + * @brief peeks at the properties under the "workflow" unprotected property + * + * @param updateActionJsonObj The JSON object of the update action JSON. + * @param outWorkflowUpdateAction The output parameter for receiving the value of "action" under "workflow". May be set to NULL if there was none in the JSON. + * @param outRootKeyPkgUrl The output parameter for receiving the value of "rootkeyPkgUrl" unprotected property from the updateAction json. Will not be set when error result is returned. + * @param outWorkflowId_optional The output parameter for receiving the value of "id" under "workflow". May be set to NULL if there was none in the JSON. + * + * @details Caller must never free workflowId. + * @returns ADUC_Result The result. + */ +ADUC_Result workflow_parse_peek_unprotected_workflow_properties( + JSON_Object* updateActionJsonObj, + ADUCITF_UpdateAction* outWorkflowUpdateAction, + char** outRootKeyPkgUrl_optional, + char** outWorkflowId_optional) +{ + ADUC_Result result = { + .ResultCode = ADUC_GeneralResult_Failure, + .ExtendedResultCode = 0, + }; + + ADUCITF_UpdateAction updateAction = ADUCITF_UpdateAction_Undefined; + const char* workflowId = NULL; + const char* rootkeyPkgUrl = NULL; + + char* tmpWorkflowId = NULL; + char* tmpRootKeyPkgUrl = NULL; + + if (json_object_dothas_value(updateActionJsonObj, ADUCITF_FIELDNAME_WORKFLOW_DOT_ACTION)) + { + updateAction = json_object_dotget_number(updateActionJsonObj, ADUCITF_FIELDNAME_WORKFLOW_DOT_ACTION); + if (updateAction == 0) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_WORKFLOW_ACTION; + goto done; + } + } + + rootkeyPkgUrl = json_object_dotget_string(updateActionJsonObj, ADUCITF_FIELDNAME_ROOTKEY_PACKAGE_URL); + if (IsNullOrEmpty(rootkeyPkgUrl)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_EMPTY_OR_MISSING_ROOTKEY_PKG_URL; + goto done; + } + + workflowId = json_object_dotget_string(updateActionJsonObj, WORKFLOW_PROPERTY_FIELD_WORKFLOW_DOT_ID); + // workflowId can be NULL in some cases. + + if (outWorkflowId_optional != NULL && workflowId != NULL) + { + tmpWorkflowId = workflow_copy_string(workflowId); + if (tmpWorkflowId == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + } + + if (outRootKeyPkgUrl_optional != NULL) + { + tmpRootKeyPkgUrl = workflow_copy_string(rootkeyPkgUrl); + if (tmpRootKeyPkgUrl == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } + } + + // Commit the optional out parameters now that nothing can goto done. + if (outWorkflowUpdateAction != NULL) + { + *outWorkflowUpdateAction = updateAction; + } + + if (outWorkflowId_optional != NULL && workflowId != NULL) + { + *outWorkflowId_optional = tmpWorkflowId; + tmpWorkflowId = NULL; + } + + if (outRootKeyPkgUrl_optional != NULL) + { + *outRootKeyPkgUrl_optional = tmpRootKeyPkgUrl; + tmpRootKeyPkgUrl = NULL; + } + + result.ResultCode = ADUC_GeneralResult_Success; + result.ExtendedResultCode = 0; + +done: + workflow_free_string(tmpWorkflowId); + workflow_free_string(tmpRootKeyPkgUrl); + + return result; +} + +/** + * @brief Helper function for checking the hash of the updatemanifest is equal to the * hash held within the signature - * @param updateActionJson JSON value created form an updateActionJsonString and contains - * both the updateManifest and the updateManifestSignature + * @param updateActionObject update action JSON object. * @returns true on success and false on failure */ -bool _Json_ValidateManifestHash(const JSON_Value* updateActionJson) +static bool Json_ValidateManifestHash(const JSON_Object* updateActionObject) { bool success = false; JSON_Value* signatureValue = NULL; char* jwtPayload = NULL; - if (updateActionJson == NULL) + if (updateActionObject == NULL) { - Log_Error("updateActionJson passed to _Json_ValidateManifestHash is NULL"); + Log_Error("NULL updateActionObject"); goto done; } - JSON_Object* updateActionObject = json_value_get_object(updateActionJson); - const char* updateManifestStr = json_object_get_string(updateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST); if (updateManifestStr == NULL) @@ -772,39 +869,313 @@ bool _Json_ValidateManifestHash(const JSON_Value* updateActionJson) } /** - * @brief A helper function for parsing workflow data from file, or from string. + * @brief Validates the update manifest signature. + * @param updateActionObject The update action JSON object. * - * @param isFile A boolean indicates whether @p source is an input file, or an input JSON string. - * @param source An input file or JSON string. - * @param validateManifest A boolean indicates whether to validate the manifest. - * @param handle An output workflow object handle. - * @return ADUC_Result + * @return ADUC_Result The result. */ -ADUC_Result _workflow_parse(bool isFile, const char* source, bool validateManifest, ADUC_WorkflowHandle* handle) +static ADUC_Result workflow_validate_update_manifest_signature(JSON_Object* updateActionObject) { - ADUC_Result result = { ADUC_GeneralResult_Failure }; - JSON_Value* updateActionJson = NULL; - char* workFolder = NULL; - STRING_HANDLE detachedUpdateManifestFilePath = NULL; - ADUC_FileEntity fileEntity; - memset(&fileEntity, 0, sizeof(fileEntity)); + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + const char* manifestSignature = NULL; + JWSResult jwsResult = JWSResult_Failed; - if (handle == NULL) + if (updateActionObject == NULL) { result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM; return result; } - *handle = NULL; + manifestSignature = json_object_get_string(updateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFESTSIGNATURE); + if (manifestSignature == NULL) + { + Log_Error("Invalid manifest. Does not contain a signature"); + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MANIFEST_VALIDATION_FAILED; + goto done; + } - ADUC_Workflow* wf = malloc(sizeof(*wf)); - if (wf == NULL) + jwsResult = VerifyJWSWithSJWK(manifestSignature); + if (jwsResult != JWSResult_Success) + { + if (jwsResult == JWSResult_DisallowedSigningKey) + { + Log_Error("Signing Key for the update metadata was on the disallowed signing key list"); + result.ExtendedResultCode = ADUC_ERC_ROOTKEY_SIGNING_KEY_IS_DISABLED; + } + else + { + result.ExtendedResultCode = MAKE_ADUC_EXTENDEDRESULTCODE_FOR_FACILITY_ADUC_FACILITY_INFRA_MGMT( + ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION, jwsResult); + } + + goto done; + } + + if (!Json_ValidateManifestHash(updateActionObject)) + { + // Handle failed hash case + Log_Error("Json_ValidateManifestHash failed"); + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MANIFEST_VALIDATION_FAILED; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; +done: + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error( + "Manifest signature validation failed with result: '%s' (%u). ERC: ADUC_COMPONENT_JWS_UPDATE_MANIFEST_VALIDATION", + jws_result_to_str(jwsResult), + jwsResult); + } + + return result; +} + +/** + * @brief Updates the workflow object's UpdateManifest JSON object based on the workflow object's UpdateAction JSON object. + * + * @param wf The workflow object. + * + * @return ADUC_Result The result + */ +static ADUC_Result UpdateWorkflowUpdateManifestObjFromUpdateActionObj(ADUC_Workflow* wf) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + if (json_object_has_value_of_type(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST, JSONString) == 1) + { + // Deserialize update manifest. + const char* updateManifestString = + json_object_get_string(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST); + if (updateManifestString == NULL) + { + char* s = json_serialize_to_string(json_object_get_wrapping_value(wf->UpdateActionObject)); + Log_Error("No Update Manifest\n%s", s); + json_free_serialized_string(s); + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_MANIFEST; + goto done; + } + + wf->UpdateManifestObject = json_value_get_object(json_parse_string(updateManifestString)); + } + // In case the Update Manifest is in a from of JSON object. + else if (json_object_has_value_of_type(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST, JSONObject)) + { + JSON_Value* v = json_object_get_value(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST); + if (v != NULL) + { + char* serialized = json_serialize_to_string(v); + wf->UpdateManifestObject = json_value_get_object(json_parse_string(serialized)); + json_free_serialized_string(serialized); + } + } + + if (wf->UpdateManifestObject == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_UPDATE_MANIFEST; + goto done; + } + + result.ResultCode = ADUC_GeneralResult_Success; +done: + + return result; +} + +/** + * @brief Get the Detached Manifest Json Obj from the downloaded detached manifest file in the sandbox work folder. + * + * @param detachedUpdateManifestFilePath The detached update manifest file path. + * @param outDetachedManifestJsonObj The output parameter for detached manifest JSON object. + * @return ADUC_Result The result. + */ +ADUC_Result GetDetachedManifestJsonObjFromSandbox( + const char* detachedUpdateManifestFilePath, JSON_Object** outDetachedManifestJsonObj) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + JSON_Value* rootValue = NULL; + const char* updateManifestString = NULL; + JSON_Object* detachedManifestJsonObj = NULL; + + rootValue = json_parse_file(detachedUpdateManifestFilePath); + if (rootValue == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST_JSON_FILE; + goto done; + } + + updateManifestString = json_object_get_string(json_value_get_object(rootValue), ADUCITF_FIELDNAME_UPDATEMANIFEST); + if (updateManifestString == NULL) + { + result.ExtendedResultCode = + ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_MISSING_UPDATEMANIFEST_PROPERTY; + goto done; + } + + detachedManifestJsonObj = json_value_get_object(json_parse_string(updateManifestString)); + if (detachedManifestJsonObj == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST; + goto done; + } + + // commit on success + *outDetachedManifestJsonObj = detachedManifestJsonObj; + detachedManifestJsonObj = NULL; + + result.ResultCode = ADUC_GeneralResult_Success; + +done: + json_value_free(rootValue); + + if (detachedManifestJsonObj != NULL) + { + json_value_free(json_object_get_wrapping_value(detachedManifestJsonObj)); + } + + if (IsAducResultCodeFailure(result.ResultCode)) + { + Log_Error("Failed getting valid detached manifest from sandbox, ERC %d", result.ExtendedResultCode); + } + + return result; +} + +/** + * @brief Replaces the existing update manifest JSON object in the workflow object with that of the detached manifest. + * + * @param workFolder The work folder download sandbox. + * @param detachedManifestFilePath The file path of detached manifest file. + * @param wf The aduc workflow in which the UpdateManifestObject will be replaced. + * + * @return ADUC_Result The result. + */ +ADUC_Result ReplaceExistingUpdateManifestWithDetachedManifest( + const char* workFolder, const char* detachedManifestFilePath, ADUC_Workflow* wf) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + JSON_Object* detachedManifestJsonObj = NULL; + + STRING_HANDLE detachedUpdateManifestFilePath = + STRING_construct_sprintf("%s/%s", workFolder, detachedManifestFilePath); + if (detachedUpdateManifestFilePath == NULL) { result.ExtendedResultCode = ADUC_ERC_NOMEM; goto done; } - memset(wf, 0, sizeof(*wf)); + result = + GetDetachedManifestJsonObjFromSandbox(STRING_c_str(detachedUpdateManifestFilePath), &detachedManifestJsonObj); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + // Replace old manifest object with detached one. + json_value_free(json_object_get_wrapping_value(wf->UpdateManifestObject)); + wf->UpdateManifestObject = detachedManifestJsonObj; + detachedManifestJsonObj = NULL; + +done: + STRING_delete(detachedUpdateManifestFilePath); + + if (detachedManifestJsonObj != NULL) + { + json_value_free(json_object_get_wrapping_value(detachedManifestJsonObj)); + } + + return result; +} + +/** + * @brief Downloads the detached v4+ update manifest and replaces existing one with it upon success. + * + * @param handle The workflow handle. + * @return ADUC_Result The result. + */ + +static ADUC_Result DownloadAndUseDetachedManifest(ADUC_Workflow* wf) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + ADUC_FileEntity* fileEntity = NULL; + const char* workFolder = NULL; + int sandboxCreateResult = -1; + + if (wf == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM; + return result; + } + + // There's only 1 file entity when the primary update manifest is detached. + if (!workflow_get_update_file(handle_from_workflow(wf), 0, fileEntity)) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MISSING_DETACHED_UPDATE_MANIFEST_ENTITY; + goto done; + } + + workFolder = workflow_get_workfolder(handle_from_workflow(wf)); + + sandboxCreateResult = ADUC_SystemUtils_MkSandboxDirRecursive(workFolder); + if (sandboxCreateResult != 0) + { + Log_Error("Unable to create folder %s, error %d", workFolder, sandboxCreateResult); + result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_DOWNLOAD_FAILED; + goto done; + } + + // Download the detached update manifest file. + result = ExtensionManager_Download( + fileEntity, + handle_from_workflow(wf), + &Default_ExtensionManager_Download_Options, + NULL /* downloadProgressCallback */); + if (IsAducResultCodeFailure(result.ResultCode)) + { + workflow_set_result_details( + handle_from_workflow(wf), "Cannot download primary detached update manifest file."); + goto done; + } + + result = ReplaceExistingUpdateManifestWithDetachedManifest(workFolder, fileEntity->TargetFilename, wf); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + +done: + if (fileEntity != NULL) + { + ADUC_FileEntity_Uninit(fileEntity); + free(fileEntity); + } + + return result; +} + +/** + * @brief A helper function for getting the JSON_Value from file or string. + * + * @param isFile A boolean indicates whether @p source is an input file, or an input JSON string. + * @param source An input file or JSON string. + * @param outJsonValue The output parameter for json value. + * + * @returns ADUC_Result The result. + */ +ADUC_Result workflow_parse_json(bool isFile, const char* source, JSON_Value** outJsonValue) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + JSON_Value* updateActionJson = NULL; + + if (source == NULL || outJsonValue == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM; + return result; + } if (isFile) { @@ -834,147 +1205,116 @@ ADUC_Result _workflow_parse(bool isFile, const char* source, bool validateManife goto done; } - JSON_Object* updateActionObject = json_value_get_object(updateActionJson); + *outJsonValue = updateActionJson; + updateActionJson = NULL; + result.ResultCode = ADUC_GeneralResult_Success; +done: + + if (updateActionJson != NULL) + { + json_value_free(updateActionJson); + } + + return result; +} + +/** + * @brief A helper function for parsing workflow data from file, or from string. + * + * @param updateActionJson The update action JSON value. + * @param validateManifest A boolean indicates whether to validate the manifest. + * @param handle An output workflow object handle. + * @return ADUC_Result The result. + */ +ADUC_Result _workflow_parse(JSON_Value* updateActionJson, bool validateManifest, ADUC_WorkflowHandle* handle) +{ + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + ADUC_Workflow* wf = NULL; + JSON_Value* updateActionJsonClone = NULL; + JSON_Object* updateActionObject = NULL; ADUCITF_UpdateAction updateAction = ADUCITF_UpdateAction_Undefined; - if (json_object_dothas_value(updateActionObject, ADUCITF_FIELDNAME_WORKFLOW_DOT_ACTION)) + + if (handle == NULL) + { + result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM; + return result; + } + + *handle = NULL; + + wf = malloc(sizeof(*wf)); + if (wf == NULL) { - updateAction = json_object_dotget_number(updateActionObject, ADUCITF_FIELDNAME_WORKFLOW_DOT_ACTION); + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; } + memset(wf, 0, sizeof(*wf)); + + updateActionJsonClone = json_value_deep_copy(updateActionJson); + updateActionJson = NULL; + + // commit ownership of cloned JSON_Value to the workflow's UpdateActionObject. + updateActionObject = json_value_get_object(updateActionJsonClone); wf->UpdateActionObject = updateActionObject; + updateActionJsonClone = NULL; + + // At this point, we have had a side-effect of committing to the + // wf->UpdateActionObject. + // + // Now, if not a cancel update action, then update the + // wf->UpdateManifestObj only after validating update manifest signature. + // + // After that, if a detached manifest exists in the manifest, then + // overwrite wf->UpdateManifestObj after downloading and verifying the + // detached manifest. // 'cancel' action doesn't contains UpdateManifest and UpdateSignature. // Skip this part. + workflow_parse_peek_unprotected_workflow_properties( + updateActionObject, &updateAction, NULL /* outRootKeyPkgUrl_optional */, NULL /* outWorkflowId_optional */); if (updateAction != ADUCITF_UpdateAction_Cancel) { + ADUC_Result tmpResult = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + // Skip signature validation if specified. // Also, some (partial) action data may not contain an UpdateAction, // e.g., Components-Update manifest that delivered as part of Bundle Updates, // We will skip the validation for these cases. - if (validateManifest && (updateAction != ADUCITF_UpdateAction_Undefined)) + if (updateAction != ADUCITF_UpdateAction_Undefined && validateManifest) { - const char* manifestSignature = - json_object_get_string(updateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFESTSIGNATURE); - if (manifestSignature == NULL) - { - Log_Error("Invalid manifest. Does not contain a signature"); - result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MANIFEST_VALIDATION_FAILED; - goto done; - } - - JWSResult jwsResult = VerifyJWSWithSJWK(manifestSignature); - if (jwsResult != JWSResult_Success) + tmpResult = workflow_validate_update_manifest_signature(updateActionObject); + if (IsAducResultCodeFailure(tmpResult.ResultCode)) { - Log_Error("Manifest signature validation failed with result: %u", jwsResult); - result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MANIFEST_VALIDATION_FAILED; - goto done; - } - - if (!_Json_ValidateManifestHash(updateActionJson)) - { - // Handle failed hash case - Log_Error("_Json_ValidateManifestHash failed"); - result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MANIFEST_VALIDATION_FAILED; + result = tmpResult; goto done; } } - // Parsing Update Manifest in a form of JSON string. - if (json_object_has_value_of_type(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST, JSONString) == 1) + tmpResult = UpdateWorkflowUpdateManifestObjFromUpdateActionObj(wf); + if (IsAducResultCodeFailure(tmpResult.ResultCode)) { - // Deserialize update manifest. - const char* updateManifestString = - json_object_get_string(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST); - if (updateManifestString == NULL) - { - char* s = json_serialize_to_string(json_object_get_wrapping_value(wf->UpdateActionObject)); - Log_Error("No Update Manifest\n%s", s); - json_free_serialized_string(s); - result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_NO_UPDATE_MANIFEST; - goto done; - } - - wf->UpdateManifestObject = json_value_get_object(json_parse_string(updateManifestString)); - } - // In case the Update Manifest is in a from of JSON object. - else if (json_object_has_value_of_type(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST, JSONObject)) - { - JSON_Value* v = json_object_get_value(wf->UpdateActionObject, ADUCITF_FIELDNAME_UPDATEMANIFEST); - if (v != NULL) - { - char* s = json_serialize_to_string(v); - wf->UpdateManifestObject = json_value_get_object(json_parse_string(s)); - } - } - - if (wf->UpdateManifestObject == NULL) - { - result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_UPDATE_MANIFEST; + result = tmpResult; goto done; } - int manifestVersion = workflow_get_update_manifest_version(handle_from_workflow(wf)); - // Starting from version 4, the update manifest can contain both embedded manifest, // or a downloadable update manifest file (files["manifest"] contains the update manifest file info) - int sandboxCreateResult = -1; - const char* detachedManifestFileId = - json_object_get_string(wf->UpdateManifestObject, UPDATE_MANIFEST_PROPERTY_FIELD_DETACHED_MANIFEST_FILE_ID); - if (!IsNullOrEmpty(detachedManifestFileId)) + if (!IsNullOrEmpty(json_object_get_string( + wf->UpdateManifestObject, UPDATE_MANIFEST_PROPERTY_FIELD_DETACHED_MANIFEST_FILE_ID))) { - // There's only 1 file entity when the primary update manifest is detached. - if (!workflow_get_update_file(handle_from_workflow(wf), 0, &fileEntity)) + tmpResult = DownloadAndUseDetachedManifest(wf); + if (IsAducResultCodeFailure(tmpResult.ResultCode)) { - result.ExtendedResultCode = - ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_MISSING_DETACHED_UPDATE_MANIFEST_ENTITY; + result = tmpResult; goto done; } - - workFolder = workflow_get_workfolder(handle_from_workflow(wf)); - - sandboxCreateResult = ADUC_SystemUtils_MkSandboxDirRecursive(workFolder); - if (sandboxCreateResult != 0) - { - Log_Error("Unable to create folder %s, error %d", workFolder, sandboxCreateResult); - result.ExtendedResultCode = - ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_DETACHED_UPDATE_MANIFEST_DOWNLOAD_FAILED; - goto done; - } - - // Download the detached update manifest file. - result = ExtensionManager_Download( - &fileEntity, handle, &Default_ExtensionManager_Download_Options, NULL /* downloadProgressCallback */); - if (IsAducResultCodeFailure(result.ResultCode)) - { - workflow_set_result_details( - handle_from_workflow(wf), "Cannot download primary detached update manifest file."); - goto done; - } - else - { - // Replace existing updateManifest with the one from detached update manifest file. - detachedUpdateManifestFilePath = - STRING_construct_sprintf("%s/%s", workFolder, fileEntity.TargetFilename); - JSON_Object* rootObj = - json_value_get_object(json_parse_file(STRING_c_str(detachedUpdateManifestFilePath))); - const char* updateManifestString = json_object_get_string(rootObj, ADUCITF_FIELDNAME_UPDATEMANIFEST); - JSON_Object* detachedManifest = json_value_get_object(json_parse_string(updateManifestString)); - json_value_free(json_object_get_wrapping_value(rootObj)); - - if (detachedManifest == NULL) - { - result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_BAD_DETACHED_UPDATE_MANIFEST; - goto done; - } - - // Free old manifest value. - json_value_free(json_object_get_wrapping_value(wf->UpdateManifestObject)); - wf->UpdateManifestObject = detachedManifest; - } } if (validateManifest) { + int manifestVersion = workflow_get_update_manifest_version(handle_from_workflow(wf)); if (manifestVersion < SUPPORTED_UPDATE_MANIFEST_VERSION_MIN || manifestVersion > SUPPORTED_UPDATE_MANIFEST_VERSION_MAX) { @@ -989,27 +1329,23 @@ ADUC_Result _workflow_parse(bool isFile, const char* source, bool validateManife } } + *handle = wf; result.ResultCode = ADUC_GeneralResult_Success; result.ExtendedResultCode = 0; done: - ADUC_FileEntity_Uninit(&fileEntity); - - STRING_delete(detachedUpdateManifestFilePath); + if (updateActionJsonClone != NULL) + { + json_value_free(updateActionJsonClone); + } if (IsAducResultCodeFailure(result.ResultCode)) { - if (updateActionJson != NULL) - { - json_value_free(updateActionJson); - } - free(wf); wf = NULL; } - *handle = wf; return result; } @@ -2099,14 +2435,14 @@ ADUC_Result _workflow_init_helper(ADUC_WorkflowHandle* handle) wf->PropertiesObject = json_value_get_object(json_value_init_object()); if (wf->PropertiesObject == NULL) { - result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_NO_MEM; + result.ExtendedResultCode = ADUC_ERC_NOMEM; goto done; } wf->ResultsObject = json_value_get_object(json_value_init_object()); if (wf->ResultsObject == NULL) { - result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_NO_MEM; + result.ExtendedResultCode = ADUC_ERC_NOMEM; goto done; } @@ -2114,7 +2450,12 @@ ADUC_Result _workflow_init_helper(ADUC_WorkflowHandle* handle) wf->InstalledUpdateId = STRING_new(); wf->Result.ResultCode = ADUC_Result_Failure; wf->Result.ExtendedResultCode = 0; - wf->ResultSuccessErc = 0; + + if ((wf->ResultExtraExtendedResultCodes = VECTOR_create(sizeof(ADUC_Result_t))) == NULL) + { + result.ExtendedResultCode = ADUC_ERC_NOMEM; + goto done; + } wf->UpdateFileInodes = NULL; @@ -2137,35 +2478,58 @@ ADUC_Result _workflow_init_helper(ADUC_WorkflowHandle* handle) return result; } -ADUC_Result workflow_init_from_file(const char* updateManifestFile, bool validateManifest, ADUC_WorkflowHandle* handle) +ADUC_Result +workflow_init_from_file(const char* updateManifestFile, bool validateManifest, ADUC_WorkflowHandle* outWorkflowHandle) { - ADUC_Result result = { ADUC_GeneralResult_Failure }; - if (updateManifestFile == NULL || handle == NULL) + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + ADUC_WorkflowHandle workflowHandle = NULL; + + JSON_Value* rootJsonValue = NULL; + + if (updateManifestFile == NULL || outWorkflowHandle == NULL) { result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM; goto done; } - result = _workflow_parse(true, updateManifestFile, validateManifest, handle); + *outWorkflowHandle = NULL; + result = workflow_parse_json(true /* isFile */, updateManifestFile, &rootJsonValue); if (IsAducResultCodeFailure(result.ResultCode)) { goto done; } - result = _workflow_init_helper(handle); + result = _workflow_parse(rootJsonValue, validateManifest, &workflowHandle); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = _workflow_init_helper(workflowHandle); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + *outWorkflowHandle = workflowHandle; + workflowHandle = NULL; done: + json_value_free(rootJsonValue); + + if (workflowHandle != NULL) + { + workflow_free(workflowHandle); + workflowHandle = NULL; + } + if (IsAducResultCodeFailure(result.ResultCode)) { Log_Error( "Failed to init workflow handle. result:%d (erc:0x%X)", result.ResultCode, result.ExtendedResultCode); - if (handle != NULL) - { - workflow_free(*handle); - *handle = NULL; - } } return result; @@ -2404,15 +2768,18 @@ bool workflow_transfer_data(ADUC_WorkflowHandle targetHandle, ADUC_WorkflowHandl /** * @brief Instantiate and initialize workflow object with info from the given jsonData. * - * @param updateManifestJson A JSON string containing update manifest data. + * @param updateManifestJsonStr A JSON string containing update manifest data. * @param validateManifest A boolean indicates whether to validate the update manifest. * @param handle An output workflow object handle. * @return ADUC_Result */ -ADUC_Result workflow_init(const char* updateManifestJson, bool validateManifest, ADUC_WorkflowHandle* handle) +ADUC_Result workflow_init(const char* updateManifestJsonStr, bool validateManifest, ADUC_WorkflowHandle* handle) { - ADUC_Result result = { ADUC_GeneralResult_Failure }; - if (updateManifestJson == NULL || handle == NULL) + ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 }; + + JSON_Value* rootJsonValue = NULL; + + if (updateManifestJsonStr == NULL || handle == NULL) { result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM; goto done; @@ -2420,7 +2787,13 @@ ADUC_Result workflow_init(const char* updateManifestJson, bool validateManifest, memset(handle, 0, sizeof(*handle)); - result = _workflow_parse(false, updateManifestJson, validateManifest, handle); + result = workflow_parse_json(false /* isFile */, updateManifestJsonStr, &rootJsonValue); + if (IsAducResultCodeFailure(result.ResultCode)) + { + goto done; + } + + result = _workflow_parse(rootJsonValue, validateManifest, handle); if (IsAducResultCodeFailure(result.ResultCode)) { goto done; @@ -2430,6 +2803,8 @@ ADUC_Result workflow_init(const char* updateManifestJson, bool validateManifest, done: + json_value_free(rootJsonValue); + if (IsAducResultCodeFailure(result.ResultCode)) { Log_Error( @@ -2586,6 +2961,12 @@ void workflow_uninit(ADUC_WorkflowHandle handle) wf->ResultDetails = NULL; STRING_delete(wf->InstalledUpdateId); wf->InstalledUpdateId = NULL; + + if (wf->ResultExtraExtendedResultCodes != NULL) + { + VECTOR_destroy(wf->ResultExtraExtendedResultCodes); + wf->ResultExtraExtendedResultCodes = NULL; + } } _workflow_free_updateaction(handle); @@ -2922,24 +3303,28 @@ ADUC_Result workflow_get_result(ADUC_WorkflowHandle handle) return wf->Result; } -void workflow_set_success_erc(ADUC_WorkflowHandle handle, ADUC_Result_t erc) +void workflow_add_erc(ADUC_WorkflowHandle handle, ADUC_Result_t erc) { ADUC_Workflow* wf = workflow_from_handle(handle); - if (wf != NULL) + if (wf != NULL && wf->ResultExtraExtendedResultCodes != NULL) { - wf->ResultSuccessErc = erc; + if (VECTOR_push_back(wf->ResultExtraExtendedResultCodes, &erc, 1) != 0) + { + Log_Warn("push ", wf->Level); + } } } -ADUC_Result_t workflow_get_success_erc(ADUC_WorkflowHandle handle) +STRING_HANDLE workflow_get_extra_ercs(ADUC_WorkflowHandle handle) { ADUC_Workflow* wf = workflow_from_handle(handle); - if (wf == NULL) + if (wf == NULL || wf->ResultExtraExtendedResultCodes == NULL) { - return 0; + return NULL; } - return wf->ResultSuccessErc; + return ADUC_ReportingUtils_StringHandleFromVectorInt32( + wf->ResultExtraExtendedResultCodes, WORKFLOW_MAX_SUCCESS_ERC); } const char* workflow_peek_result_details(ADUC_WorkflowHandle handle) @@ -3662,3 +4047,31 @@ void workflow_set_force_update(ADUC_WorkflowHandle handle, bool forceUpdate) wf->ForceUpdate = forceUpdate; } } + +bool workflow_init_workflow_handle(ADUC_WorkflowData* workflowData) +{ + ADUC_Workflow* wf = malloc(sizeof(*wf)); + if (wf == NULL) + { + return false; + } + + memset(wf, 0, sizeof(*wf)); + + workflowData->WorkflowHandle = wf; + return true; +} + +bool workflow_set_update_action_object(ADUC_WorkflowHandle handle, JSON_Object* jsonObj) +{ + ADUC_Workflow* wf = workflow_from_handle(handle); + if (wf != NULL) + { + wf->UpdateActionObject = jsonObj; + return true; + } + + return false; +} + +EXTERN_C_END diff --git a/src/utils/workflow_utils/tests/CMakeLists.txt b/src/utils/workflow_utils/tests/CMakeLists.txt index 448b384fb..7209efb43 100644 --- a/src/utils/workflow_utils/tests/CMakeLists.txt +++ b/src/utils/workflow_utils/tests/CMakeLists.txt @@ -17,11 +17,16 @@ target_sources (${PROJECT_NAME} PRIVATE main.cpp workflow_utils_ut.cpp target_include_directories (${PROJECT_NAME} PUBLIC inc ${ADUC_EXPORT_INCLUDES}) -target_link_libraries (${PROJECT_NAME} PRIVATE aduc::parser_utils aduc::workflow_utils - Catch2::Catch2) +target_link_libraries (${PROJECT_NAME} PRIVATE aduc::parser_utils aduc::string_utils + aduc::test_utils aduc::workflow_utils Catch2::Catch2) target_link_aziotsharedutil (${PROJECT_NAME} PRIVATE) +# Windows needs all EXEs to have links to all potential libraries so this is included here +if (WIN32) + target_link_dosdk (${PROJECT_NAME} PRIVATE) +endif () + target_link_libraries (${PROJECT_NAME} PRIVATE libaducpal) target_compile_definitions (${PROJECT_NAME} diff --git a/src/utils/workflow_utils/tests/workflow_get_update_file_ut.cpp b/src/utils/workflow_utils/tests/workflow_get_update_file_ut.cpp index 02db7c66c..972ef6b1f 100644 --- a/src/utils/workflow_utils/tests/workflow_get_update_file_ut.cpp +++ b/src/utils/workflow_utils/tests/workflow_get_update_file_ut.cpp @@ -11,7 +11,8 @@ #include using Catch::Matchers::Equals; -#include // ADUC_FileEntity_Uninit +#include +#include #include #include #include @@ -33,14 +34,6 @@ static std::string get_twin_desired_json_path() return path; } -static std::string slurp(const std::string& path) -{ - std::ifstream f(path); - std::stringstream stream; - stream << f.rdbuf(); - return stream.str(); -} - TEST_CASE("workflow_get_update_file with download handler") { const char* targetUpdateFileId = "f222b9ffefaaac577"; @@ -64,7 +57,7 @@ TEST_CASE("workflow_get_update_file with download handler") std::regex_replace(serializedUpdateManifest, std::regex("DELTA_UPDATE_FILE_ID"), deltaUpdateFileId); serializedUpdateManifest = std::regex_replace(serializedUpdateManifest, std::regex("\""), "\\\""); - std::string desired = slurp(get_twin_desired_json_path()); + std::string desired = aduc::FileTestUtils_slurpFile(get_twin_desired_json_path()); desired = std::regex_replace(desired, std::regex("UPDATE_MANIFEST_SIGNATURE"), "foo"); desired = std::regex_replace(desired, std::regex("TARGET_UPDATE_FILE_ID"), targetUpdateFileId); desired = std::regex_replace(desired, std::regex("DELTA_UPDATE_FILE_ID"), deltaUpdateFileId); diff --git a/src/utils/workflow_utils/tests/workflow_utils_ut.cpp b/src/utils/workflow_utils/tests/workflow_utils_ut.cpp index 48b171fd3..33d03ebaf 100644 --- a/src/utils/workflow_utils/tests/workflow_utils_ut.cpp +++ b/src/utils/workflow_utils/tests/workflow_utils_ut.cpp @@ -7,6 +7,7 @@ */ #include "aduc/parser_utils.h" #include "aduc/result.h" +#include "aduc/string_handle_wrapper.hpp" #include "aduc/workflow_utils.h" #include @@ -18,38 +19,40 @@ using Catch::Matchers::Equals; // clang-format off const char* action_parent_update = - R"( { )" - R"( "workflow": { )" - R"( "action": 3, )" - R"( "id": "dcb112da-bfc9-47b7-b7ed-617feba1e6c4" )" - R"( }, )" - R"( "updateManifest": "{\"manifestVersion\":\"5\",\"updateId\":{\"provider\":\"Contoso\",\"name\":\"Virtual-Vacuum\",\"version\":\"20.0\"},\"compatibility\":[{\"deviceManufacturer\":\"contoso\",\"deviceModel\":\"virtual-vacuum-v1\"}],\"instructions\":{\"steps\":[{\"handler\":\"microsoft/apt:1\",\"files\":[\"f483750ebb885d32c\"],\"handlerProperties\":{\"installedCriteria\":\"apt-update-tree-1.0\"}},{\"type\":\"reference\",\"detachedManifestFileId\":\"f222b9ffefaaac577\"}]},\"files\":{\"f483750ebb885d32c\":{\"fileName\":\"apt-manifest-tree-1.0.json\",\"sizeInBytes\":136,\"hashes\":{\"sha256\":\"Uk1vsEL/nT4btMngo0YSJjheOL2aqm6/EAFhzPb0rXs=\"}},\"f222b9ffefaaac577\":{\"fileName\":\"contoso.contoso-virtual-motors.1.1.updatemanifest.json\",\"sizeInBytes\":1031,\"hashes\":{\"sha256\":\"9Rnjw7ThZhGacOGn3uvvVq0ccQTHc/UFSL9khR2oKsc=\"}}},\"createdDateTime\":\"2022-01-27T13:45:05.8993329Z\"}", )" - R"( "updateManifestSignature": "eyJhbGciOiJSUzI1NiIsInNqd2siOiJleUpoYkdjaU9pSlNVekkxTmlJc0ltdHBaQ0k2SWtGRVZTNHlNREEzTURJdVVpSjkuZXlKcmRIa2lPaUpTVTBFaUxDSnVJam9pYkV4bWMwdHZPRmwwWW1Oak1sRXpUalV3VlhSTVNXWlhVVXhXVTBGRlltTm9LMFl2WTJVM1V6Rlpja3BvV0U5VGNucFRaa051VEhCVmFYRlFWSGMwZWxndmRHbEJja0ZGZFhrM1JFRmxWVzVGU0VWamVEZE9hM2QzZVRVdk9IcExaV3AyWTBWWWNFRktMMlV6UWt0SE5FVTBiMjVtU0ZGRmNFOXplSGRQUzBWbFJ6QkhkamwzVjB3emVsUmpUblprUzFoUFJGaEdNMVZRWlVveGIwZGlVRkZ0Y3pKNmJVTktlRUppZEZOSldVbDBiWFpwWTNneVpXdGtWbnBYUm5jdmRrdFVUblZMYXpob2NVczNTRkptYWs5VlMzVkxXSGxqSzNsSVVVa3dZVVpDY2pKNmEyc3plR2d4ZEVWUFN6azRWMHBtZUdKamFsQnpSRTgyWjNwWmVtdFlla05OZW1Fd1R6QkhhV0pDWjB4QlZGUTVUV1k0V1ZCd1dVY3lhblpQWVVSVmIwTlJiakpWWTFWU1RtUnNPR2hLWW5scWJscHZNa3B5SzFVNE5IbDFjVTlyTjBZMFdubFRiMEoyTkdKWVNrZ3lXbEpTV2tab0wzVlRiSE5XT1hkU2JWbG9XWEoyT1RGRVdtbHhhemhJVWpaRVUyeHVabTVsZFRJNFJsUm9SVzF0YjNOVlRUTnJNbGxNYzBKak5FSnZkWEIwTTNsaFNEaFpia3BVTnpSMU16TjFlakU1TDAxNlZIVnFTMmMzVkdGcE1USXJXR0owYmxwRU9XcFVSMkY1U25Sc2FFWmxWeXRJUXpVM1FYUkJSbHBvY1ZsM2VVZHJXQ3M0TTBGaFVGaGFOR0V4VHpoMU1qTk9WVWQxTWtGd04yOU5NVTR3ZVVKS0swbHNUM29pTENKbElqb2lRVkZCUWlJc0ltRnNaeUk2SWxKVE1qVTJJaXdpYTJsa0lqb2lRVVJWTGpJeE1EWXdPUzVTTGxNaWZRLlJLS2VBZE02dGFjdWZpSVU3eTV2S3dsNFpQLURMNnEteHlrTndEdkljZFpIaTBIa2RIZ1V2WnoyZzZCTmpLS21WTU92dXp6TjhEczhybXo1dnMwT1RJN2tYUG1YeDZFLUYyUXVoUXNxT3J5LS1aN2J3TW5LYTNkZk1sbkthWU9PdURtV252RWMyR0hWdVVTSzREbmw0TE9vTTQxOVlMNThWTDAtSEthU18xYmNOUDhXYjVZR08xZXh1RmpiVGtIZkNIU0duVThJeUFjczlGTjhUT3JETHZpVEtwcWtvM3RiSUwxZE1TN3NhLWJkZExUVWp6TnVLTmFpNnpIWTdSanZGbjhjUDN6R2xjQnN1aVQ0XzVVaDZ0M05rZW1UdV9tZjdtZUFLLTBTMTAzMFpSNnNTR281azgtTE1sX0ZaUmh4djNFZFNtR2RBUTNlMDVMRzNnVVAyNzhTQWVzWHhNQUlHWmcxUFE3aEpoZGZHdmVGanJNdkdTSVFEM09wRnEtZHREcEFXbUo2Zm5sZFA1UWxYek5tQkJTMlZRQUtXZU9BYjh0Yjl5aVhsemhtT1dLRjF4SzlseHpYUG9GNmllOFRUWlJ4T0hxTjNiSkVISkVoQmVLclh6YkViV2tFNm4zTEoxbkd5M1htUlVFcER0Umdpa0tBUzZybFhFT0VneXNjIn0.eyJzaGEyNTYiOiJqSW12eGpsc2pqZ29JeUJuYThuZTk2d0RYYlVsU3N6eGFoM0NibkF6STFJPSJ9.PzpvU13h6VhN8VHXUTYKAlpDW5t3JaQ-gs895_Q10XshKPYpeZUtViXGHGC-aQSQAYPhhYV-lLia9niXzZz4Qs4ehwFLHJfkmKR8eRwWvoOgJtAY0IIUA_8SeShmoOc9cdpC35N3OeaM4hV9shxvvrphDib5sLpkrv3LQrt3DHvK_L2n0HsybC-pwS7MzaSUIYoU-fXwZo6x3z7IbSaSNwS0P-50qeV99Mc0AUSIvB26GjmjZ2gEH5R3YD9kp0DOrYvE5tIymVHPTqkmunv2OrjKu2UOhNj8Om3RoVzxIkVM89cVGb1u1yB2kxEmXogXPz64cKqQWm22tV-jalS4dAc_1p9A9sKzZ632HxnlavOBjTKDGFgM95gg8M5npXBP3QIvkwW3yervCukViRUKIm-ljpDmnBJsZTMx0uzTaAk5XgoCUCADuLLol8EXB-0V4m2w-6tV6kAzRiwkqw1PRrGqplf-gmfU7TuFlQ142-EZLU5rK_dAiQRXx-f7LxNH", )" - R"( "fileUrls": { )" - R"( "f483750ebb885d32c": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/e5cc19d5e9174c93ada35cc315f1fb1d/apt-manifest-tree-1.0.json", )" - R"( "f222b9ffefaaac577": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/31c38c3340a84e38ae8d30ce340f4a49/contoso.contoso-virtual-motors.1.1.updatemanifest.json", )" - R"( "f2c5d1f3b0295db0f": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/9ff068f7c2bf43eb9561da14a7cbcecd/motor-firmware-1.1.json", )" - R"( "f13b5435aab7c18da": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/c02058a476a242d7bc0e3c576c180051/contoso-motor-installscript.sh" )" - R"( } )" - R"( } )"; + R"( { )" + R"( "rootKeyPackageUrl": "http://foo.bar/rootkeypkg.json", )" + R"( "workflow": { )" + R"( "action": 3, )" + R"( "id": "dcb112da-bfc9-47b7-b7ed-617feba1e6c4" )" + R"( }, )" + R"( "updateManifest": "{\"manifestVersion\":\"5\",\"updateId\":{\"provider\":\"Contoso\",\"name\":\"Virtual-Vacuum\",\"version\":\"20.0\"},\"compatibility\":[{\"deviceManufacturer\":\"contoso\",\"deviceModel\":\"virtual-vacuum-v1\"}],\"instructions\":{\"steps\":[{\"handler\":\"microsoft/apt:1\",\"files\":[\"f483750ebb885d32c\"],\"handlerProperties\":{\"installedCriteria\":\"apt-update-tree-1.0\"}},{\"type\":\"reference\",\"detachedManifestFileId\":\"f222b9ffefaaac577\"}]},\"files\":{\"f483750ebb885d32c\":{\"fileName\":\"apt-manifest-tree-1.0.json\",\"sizeInBytes\":136,\"hashes\":{\"sha256\":\"Uk1vsEL/nT4btMngo0YSJjheOL2aqm6/EAFhzPb0rXs=\"}},\"f222b9ffefaaac577\":{\"fileName\":\"contoso.contoso-virtual-motors.1.1.updatemanifest.json\",\"sizeInBytes\":1031,\"hashes\":{\"sha256\":\"9Rnjw7ThZhGacOGn3uvvVq0ccQTHc/UFSL9khR2oKsc=\"}}},\"createdDateTime\":\"2022-01-27T13:45:05.8993329Z\"}", )" + R"( "updateManifestSignature": "eyJhbGciOiJSUzI1NiIsInNqd2siOiJleUpoYkdjaU9pSlNVekkxTmlJc0ltdHBaQ0k2SWtGRVZTNHlNREEzTURJdVVpSjkuZXlKcmRIa2lPaUpTVTBFaUxDSnVJam9pYkV4bWMwdHZPRmwwWW1Oak1sRXpUalV3VlhSTVNXWlhVVXhXVTBGRlltTm9LMFl2WTJVM1V6Rlpja3BvV0U5VGNucFRaa051VEhCVmFYRlFWSGMwZWxndmRHbEJja0ZGZFhrM1JFRmxWVzVGU0VWamVEZE9hM2QzZVRVdk9IcExaV3AyWTBWWWNFRktMMlV6UWt0SE5FVTBiMjVtU0ZGRmNFOXplSGRQUzBWbFJ6QkhkamwzVjB3emVsUmpUblprUzFoUFJGaEdNMVZRWlVveGIwZGlVRkZ0Y3pKNmJVTktlRUppZEZOSldVbDBiWFpwWTNneVpXdGtWbnBYUm5jdmRrdFVUblZMYXpob2NVczNTRkptYWs5VlMzVkxXSGxqSzNsSVVVa3dZVVpDY2pKNmEyc3plR2d4ZEVWUFN6azRWMHBtZUdKamFsQnpSRTgyWjNwWmVtdFlla05OZW1Fd1R6QkhhV0pDWjB4QlZGUTVUV1k0V1ZCd1dVY3lhblpQWVVSVmIwTlJiakpWWTFWU1RtUnNPR2hLWW5scWJscHZNa3B5SzFVNE5IbDFjVTlyTjBZMFdubFRiMEoyTkdKWVNrZ3lXbEpTV2tab0wzVlRiSE5XT1hkU2JWbG9XWEoyT1RGRVdtbHhhemhJVWpaRVUyeHVabTVsZFRJNFJsUm9SVzF0YjNOVlRUTnJNbGxNYzBKak5FSnZkWEIwTTNsaFNEaFpia3BVTnpSMU16TjFlakU1TDAxNlZIVnFTMmMzVkdGcE1USXJXR0owYmxwRU9XcFVSMkY1U25Sc2FFWmxWeXRJUXpVM1FYUkJSbHBvY1ZsM2VVZHJXQ3M0TTBGaFVGaGFOR0V4VHpoMU1qTk9WVWQxTWtGd04yOU5NVTR3ZVVKS0swbHNUM29pTENKbElqb2lRVkZCUWlJc0ltRnNaeUk2SWxKVE1qVTJJaXdpYTJsa0lqb2lRVVJWTGpJeE1EWXdPUzVTTGxNaWZRLlJLS2VBZE02dGFjdWZpSVU3eTV2S3dsNFpQLURMNnEteHlrTndEdkljZFpIaTBIa2RIZ1V2WnoyZzZCTmpLS21WTU92dXp6TjhEczhybXo1dnMwT1RJN2tYUG1YeDZFLUYyUXVoUXNxT3J5LS1aN2J3TW5LYTNkZk1sbkthWU9PdURtV252RWMyR0hWdVVTSzREbmw0TE9vTTQxOVlMNThWTDAtSEthU18xYmNOUDhXYjVZR08xZXh1RmpiVGtIZkNIU0duVThJeUFjczlGTjhUT3JETHZpVEtwcWtvM3RiSUwxZE1TN3NhLWJkZExUVWp6TnVLTmFpNnpIWTdSanZGbjhjUDN6R2xjQnN1aVQ0XzVVaDZ0M05rZW1UdV9tZjdtZUFLLTBTMTAzMFpSNnNTR281azgtTE1sX0ZaUmh4djNFZFNtR2RBUTNlMDVMRzNnVVAyNzhTQWVzWHhNQUlHWmcxUFE3aEpoZGZHdmVGanJNdkdTSVFEM09wRnEtZHREcEFXbUo2Zm5sZFA1UWxYek5tQkJTMlZRQUtXZU9BYjh0Yjl5aVhsemhtT1dLRjF4SzlseHpYUG9GNmllOFRUWlJ4T0hxTjNiSkVISkVoQmVLclh6YkViV2tFNm4zTEoxbkd5M1htUlVFcER0Umdpa0tBUzZybFhFT0VneXNjIn0.eyJzaGEyNTYiOiJqSW12eGpsc2pqZ29JeUJuYThuZTk2d0RYYlVsU3N6eGFoM0NibkF6STFJPSJ9.PzpvU13h6VhN8VHXUTYKAlpDW5t3JaQ-gs895_Q10XshKPYpeZUtViXGHGC-aQSQAYPhhYV-lLia9niXzZz4Qs4ehwFLHJfkmKR8eRwWvoOgJtAY0IIUA_8SeShmoOc9cdpC35N3OeaM4hV9shxvvrphDib5sLpkrv3LQrt3DHvK_L2n0HsybC-pwS7MzaSUIYoU-fXwZo6x3z7IbSaSNwS0P-50qeV99Mc0AUSIvB26GjmjZ2gEH5R3YD9kp0DOrYvE5tIymVHPTqkmunv2OrjKu2UOhNj8Om3RoVzxIkVM89cVGb1u1yB2kxEmXogXPz64cKqQWm22tV-jalS4dAc_1p9A9sKzZ632HxnlavOBjTKDGFgM95gg8M5npXBP3QIvkwW3yervCukViRUKIm-ljpDmnBJsZTMx0uzTaAk5XgoCUCADuLLol8EXB-0V4m2w-6tV6kAzRiwkqw1PRrGqplf-gmfU7TuFlQ142-EZLU5rK_dAiQRXx-f7LxNH", )" + R"( "fileUrls": { )" + R"( "f483750ebb885d32c": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/e5cc19d5e9174c93ada35cc315f1fb1d/apt-manifest-tree-1.0.json", )" + R"( "f222b9ffefaaac577": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/31c38c3340a84e38ae8d30ce340f4a49/contoso.contoso-virtual-motors.1.1.updatemanifest.json", )" + R"( "f2c5d1f3b0295db0f": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/9ff068f7c2bf43eb9561da14a7cbcecd/motor-firmware-1.1.json", )" + R"( "f13b5435aab7c18da": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/c02058a476a242d7bc0e3c576c180051/contoso-motor-installscript.sh" )" + R"( } )" + R"( } )"; const char* action_child_update_0 = R"( { "updateManifest":"{\"manifestVersion\":\"4\",\"updateId\":{\"provider\":\"contoso\",\"name\":\"contoso-virtual-motors\",\"version\":\"1.1\"},\"compatibility\":[{\"group\":\"motors\"}],\"instructions\":{\"steps\":[{\"handler\":\"microsoft/script:1\",\"files\":[\"f13b5435aab7c18da\",\"f2c5d1f3b0295db0f\"],\"handlerProperties\":{\"scriptFileName\":\"contoso-motor-installscript.sh\",\"arguments\":\"--firmware-file motor-firmware-1.1.json --component-name --component-name-val --component-group --component-group-val --component-prop path --component-prop-val path\",\"installedCriteria\":\"contoso-contoso-virtual-motors-1.1-step-1\"}}]},\"files\":{\"f13b5435aab7c18da\":{\"fileName\":\"contoso-motor-installscript.sh\",\"sizeInBytes\":27030,\"hashes\":{\"sha256\":\"DYb4/+P3mq2yjq6n987msufTo3GUb5tpMtk+f7IeHx0=\"}},\"f2c5d1f3b0295db0f\":{\"fileName\":\"motor-firmware-1.1.json\",\"sizeInBytes\":123,\"hashes\":{\"sha256\":\"b8CC9E/93hUuMT19VjGVLDWGShq4GzpMYBO8vzlej74=\"}}},\"createdDateTime\":\"2022-01-27T13:45:05.8836909Z\"}"} )"; const char* action_no_update_action_data = - R"( { )" - R"( "workflow": { )" - R"( "id": "aaaaaaaa-bfc9-47b7-b7ed-617feba1e6c4" )" - R"( }, )" - R"( "updateManifest": "{\"manifestVersion\":\"4\",\"updateId\":{\"provider\":\"Contoso\",\"name\":\"Virtual-Vacuum\",\"version\":\"20.0\"},\"compatibility\":[{\"deviceManufacturer\":\"contoso\",\"deviceModel\":\"virtual-vacuum-v1\"}],\"instructions\":{\"steps\":[{\"handler\":\"microsoft/apt:1\",\"files\":[\"f483750ebb885d32c\"],\"handlerProperties\":{\"installedCriteria\":\"apt-update-tree-1.0\"}},{\"type\":\"reference\",\"detachedManifestFileId\":\"f222b9ffefaaac577\"}]},\"files\":{\"f483750ebb885d32c\":{\"fileName\":\"apt-manifest-tree-1.0.json\",\"sizeInBytes\":136,\"hashes\":{\"sha256\":\"Uk1vsEL/nT4btMngo0YSJjheOL2aqm6/EAFhzPb0rXs=\"}},\"f222b9ffefaaac577\":{\"fileName\":\"contoso.contoso-virtual-motors.1.1.updatemanifest.json\",\"sizeInBytes\":1031,\"hashes\":{\"sha256\":\"9Rnjw7ThZhGacOGn3uvvVq0ccQTHc/UFSL9khR2oKsc=\"}}},\"createdDateTime\":\"2022-01-27T13:45:05.8993329Z\"}", )" - R"( "updateManifestSignature": "eyJhbGciOiJSUzI1NiIsInNqd2siOiJleUpoYkdjaU9pSlNVekkxTmlJc0ltdHBaQ0k2SWtGRVZTNHlNREEzTURJdVVpSjkuZXlKcmRIa2lPaUpTVTBFaUxDSnVJam9pYkV4bWMwdHZPRmwwWW1Oak1sRXpUalV3VlhSTVNXWlhVVXhXVTBGRlltTm9LMFl2WTJVM1V6Rlpja3BvV0U5VGNucFRaa051VEhCVmFYRlFWSGMwZWxndmRHbEJja0ZGZFhrM1JFRmxWVzVGU0VWamVEZE9hM2QzZVRVdk9IcExaV3AyWTBWWWNFRktMMlV6UWt0SE5FVTBiMjVtU0ZGRmNFOXplSGRQUzBWbFJ6QkhkamwzVjB3emVsUmpUblprUzFoUFJGaEdNMVZRWlVveGIwZGlVRkZ0Y3pKNmJVTktlRUppZEZOSldVbDBiWFpwWTNneVpXdGtWbnBYUm5jdmRrdFVUblZMYXpob2NVczNTRkptYWs5VlMzVkxXSGxqSzNsSVVVa3dZVVpDY2pKNmEyc3plR2d4ZEVWUFN6azRWMHBtZUdKamFsQnpSRTgyWjNwWmVtdFlla05OZW1Fd1R6QkhhV0pDWjB4QlZGUTVUV1k0V1ZCd1dVY3lhblpQWVVSVmIwTlJiakpWWTFWU1RtUnNPR2hLWW5scWJscHZNa3B5SzFVNE5IbDFjVTlyTjBZMFdubFRiMEoyTkdKWVNrZ3lXbEpTV2tab0wzVlRiSE5XT1hkU2JWbG9XWEoyT1RGRVdtbHhhemhJVWpaRVUyeHVabTVsZFRJNFJsUm9SVzF0YjNOVlRUTnJNbGxNYzBKak5FSnZkWEIwTTNsaFNEaFpia3BVTnpSMU16TjFlakU1TDAxNlZIVnFTMmMzVkdGcE1USXJXR0owYmxwRU9XcFVSMkY1U25Sc2FFWmxWeXRJUXpVM1FYUkJSbHBvY1ZsM2VVZHJXQ3M0TTBGaFVGaGFOR0V4VHpoMU1qTk9WVWQxTWtGd04yOU5NVTR3ZVVKS0swbHNUM29pTENKbElqb2lRVkZCUWlJc0ltRnNaeUk2SWxKVE1qVTJJaXdpYTJsa0lqb2lRVVJWTGpJeE1EWXdPUzVTTGxNaWZRLlJLS2VBZE02dGFjdWZpSVU3eTV2S3dsNFpQLURMNnEteHlrTndEdkljZFpIaTBIa2RIZ1V2WnoyZzZCTmpLS21WTU92dXp6TjhEczhybXo1dnMwT1RJN2tYUG1YeDZFLUYyUXVoUXNxT3J5LS1aN2J3TW5LYTNkZk1sbkthWU9PdURtV252RWMyR0hWdVVTSzREbmw0TE9vTTQxOVlMNThWTDAtSEthU18xYmNOUDhXYjVZR08xZXh1RmpiVGtIZkNIU0duVThJeUFjczlGTjhUT3JETHZpVEtwcWtvM3RiSUwxZE1TN3NhLWJkZExUVWp6TnVLTmFpNnpIWTdSanZGbjhjUDN6R2xjQnN1aVQ0XzVVaDZ0M05rZW1UdV9tZjdtZUFLLTBTMTAzMFpSNnNTR281azgtTE1sX0ZaUmh4djNFZFNtR2RBUTNlMDVMRzNnVVAyNzhTQWVzWHhNQUlHWmcxUFE3aEpoZGZHdmVGanJNdkdTSVFEM09wRnEtZHREcEFXbUo2Zm5sZFA1UWxYek5tQkJTMlZRQUtXZU9BYjh0Yjl5aVhsemhtT1dLRjF4SzlseHpYUG9GNmllOFRUWlJ4T0hxTjNiSkVISkVoQmVLclh6YkViV2tFNm4zTEoxbkd5M1htUlVFcER0Umdpa0tBUzZybFhFT0VneXNjIn0.eyJzaGEyNTYiOiJqSW12eGpsc2pqZ29JeUJuYThuZTk2d0RYYlVsU3N6eGFoM0NibkF6STFJPSJ9.PzpvU13h6VhN8VHXUTYKAlpDW5t3JaQ-gs895_Q10XshKPYpeZUtViXGHGC-aQSQAYPhhYV-lLia9niXzZz4Qs4ehwFLHJfkmKR8eRwWvoOgJtAY0IIUA_8SeShmoOc9cdpC35N3OeaM4hV9shxvvrphDib5sLpkrv3LQrt3DHvK_L2n0HsybC-pwS7MzaSUIYoU-fXwZo6x3z7IbSaSNwS0P-50qeV99Mc0AUSIvB26GjmjZ2gEH5R3YD9kp0DOrYvE5tIymVHPTqkmunv2OrjKu2UOhNj8Om3RoVzxIkVM89cVGb1u1yB2kxEmXogXPz64cKqQWm22tV-jalS4dAc_1p9A9sKzZ632HxnlavOBjTKDGFgM95gg8M5npXBP3QIvkwW3yervCukViRUKIm-ljpDmnBJsZTMx0uzTaAk5XgoCUCADuLLol8EXB-0V4m2w-6tV6kAzRiwkqw1PRrGqplf-gmfU7TuFlQ142-EZLU5rK_dAiQRXx-f7LxNH", )" - R"( "fileUrls": { )" - R"( "f483750ebb885d32c": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/e5cc19d5e9174c93ada35cc315f1fb1d/apt-manifest-tree-1.0.json", )" - R"( "f222b9ffefaaac577": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/31c38c3340a84e38ae8d30ce340f4a49/contoso.contoso-virtual-motors.1.1.updatemanifest.json", )" - R"( "f2c5d1f3b0295db0f": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/9ff068f7c2bf43eb9561da14a7cbcecd/motor-firmware-1.1.json", )" - R"( "f13b5435aab7c18da": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/c02058a476a242d7bc0e3c576c180051/contoso-motor-installscript.sh" )" - R"( } )" - R"( } )"; + R"( { )" + R"( "rootKeyPackageUrl": "http://foo.bar/rootkeypkg.json", )" + R"( "workflow": { )" + R"( "id": "aaaaaaaa-bfc9-47b7-b7ed-617feba1e6c4" )" + R"( }, )" + R"( "updateManifest": "{\"manifestVersion\":\"4\",\"updateId\":{\"provider\":\"Contoso\",\"name\":\"Virtual-Vacuum\",\"version\":\"20.0\"},\"compatibility\":[{\"deviceManufacturer\":\"contoso\",\"deviceModel\":\"virtual-vacuum-v1\"}],\"instructions\":{\"steps\":[{\"handler\":\"microsoft/apt:1\",\"files\":[\"f483750ebb885d32c\"],\"handlerProperties\":{\"installedCriteria\":\"apt-update-tree-1.0\"}},{\"type\":\"reference\",\"detachedManifestFileId\":\"f222b9ffefaaac577\"}]},\"files\":{\"f483750ebb885d32c\":{\"fileName\":\"apt-manifest-tree-1.0.json\",\"sizeInBytes\":136,\"hashes\":{\"sha256\":\"Uk1vsEL/nT4btMngo0YSJjheOL2aqm6/EAFhzPb0rXs=\"}},\"f222b9ffefaaac577\":{\"fileName\":\"contoso.contoso-virtual-motors.1.1.updatemanifest.json\",\"sizeInBytes\":1031,\"hashes\":{\"sha256\":\"9Rnjw7ThZhGacOGn3uvvVq0ccQTHc/UFSL9khR2oKsc=\"}}},\"createdDateTime\":\"2022-01-27T13:45:05.8993329Z\"}", )" + R"( "updateManifestSignature": "eyJhbGciOiJSUzI1NiIsInNqd2siOiJleUpoYkdjaU9pSlNVekkxTmlJc0ltdHBaQ0k2SWtGRVZTNHlNREEzTURJdVVpSjkuZXlKcmRIa2lPaUpTVTBFaUxDSnVJam9pYkV4bWMwdHZPRmwwWW1Oak1sRXpUalV3VlhSTVNXWlhVVXhXVTBGRlltTm9LMFl2WTJVM1V6Rlpja3BvV0U5VGNucFRaa051VEhCVmFYRlFWSGMwZWxndmRHbEJja0ZGZFhrM1JFRmxWVzVGU0VWamVEZE9hM2QzZVRVdk9IcExaV3AyWTBWWWNFRktMMlV6UWt0SE5FVTBiMjVtU0ZGRmNFOXplSGRQUzBWbFJ6QkhkamwzVjB3emVsUmpUblprUzFoUFJGaEdNMVZRWlVveGIwZGlVRkZ0Y3pKNmJVTktlRUppZEZOSldVbDBiWFpwWTNneVpXdGtWbnBYUm5jdmRrdFVUblZMYXpob2NVczNTRkptYWs5VlMzVkxXSGxqSzNsSVVVa3dZVVpDY2pKNmEyc3plR2d4ZEVWUFN6azRWMHBtZUdKamFsQnpSRTgyWjNwWmVtdFlla05OZW1Fd1R6QkhhV0pDWjB4QlZGUTVUV1k0V1ZCd1dVY3lhblpQWVVSVmIwTlJiakpWWTFWU1RtUnNPR2hLWW5scWJscHZNa3B5SzFVNE5IbDFjVTlyTjBZMFdubFRiMEoyTkdKWVNrZ3lXbEpTV2tab0wzVlRiSE5XT1hkU2JWbG9XWEoyT1RGRVdtbHhhemhJVWpaRVUyeHVabTVsZFRJNFJsUm9SVzF0YjNOVlRUTnJNbGxNYzBKak5FSnZkWEIwTTNsaFNEaFpia3BVTnpSMU16TjFlakU1TDAxNlZIVnFTMmMzVkdGcE1USXJXR0owYmxwRU9XcFVSMkY1U25Sc2FFWmxWeXRJUXpVM1FYUkJSbHBvY1ZsM2VVZHJXQ3M0TTBGaFVGaGFOR0V4VHpoMU1qTk9WVWQxTWtGd04yOU5NVTR3ZVVKS0swbHNUM29pTENKbElqb2lRVkZCUWlJc0ltRnNaeUk2SWxKVE1qVTJJaXdpYTJsa0lqb2lRVVJWTGpJeE1EWXdPUzVTTGxNaWZRLlJLS2VBZE02dGFjdWZpSVU3eTV2S3dsNFpQLURMNnEteHlrTndEdkljZFpIaTBIa2RIZ1V2WnoyZzZCTmpLS21WTU92dXp6TjhEczhybXo1dnMwT1RJN2tYUG1YeDZFLUYyUXVoUXNxT3J5LS1aN2J3TW5LYTNkZk1sbkthWU9PdURtV252RWMyR0hWdVVTSzREbmw0TE9vTTQxOVlMNThWTDAtSEthU18xYmNOUDhXYjVZR08xZXh1RmpiVGtIZkNIU0duVThJeUFjczlGTjhUT3JETHZpVEtwcWtvM3RiSUwxZE1TN3NhLWJkZExUVWp6TnVLTmFpNnpIWTdSanZGbjhjUDN6R2xjQnN1aVQ0XzVVaDZ0M05rZW1UdV9tZjdtZUFLLTBTMTAzMFpSNnNTR281azgtTE1sX0ZaUmh4djNFZFNtR2RBUTNlMDVMRzNnVVAyNzhTQWVzWHhNQUlHWmcxUFE3aEpoZGZHdmVGanJNdkdTSVFEM09wRnEtZHREcEFXbUo2Zm5sZFA1UWxYek5tQkJTMlZRQUtXZU9BYjh0Yjl5aVhsemhtT1dLRjF4SzlseHpYUG9GNmllOFRUWlJ4T0hxTjNiSkVISkVoQmVLclh6YkViV2tFNm4zTEoxbkd5M1htUlVFcER0Umdpa0tBUzZybFhFT0VneXNjIn0.eyJzaGEyNTYiOiJqSW12eGpsc2pqZ29JeUJuYThuZTk2d0RYYlVsU3N6eGFoM0NibkF6STFJPSJ9.PzpvU13h6VhN8VHXUTYKAlpDW5t3JaQ-gs895_Q10XshKPYpeZUtViXGHGC-aQSQAYPhhYV-lLia9niXzZz4Qs4ehwFLHJfkmKR8eRwWvoOgJtAY0IIUA_8SeShmoOc9cdpC35N3OeaM4hV9shxvvrphDib5sLpkrv3LQrt3DHvK_L2n0HsybC-pwS7MzaSUIYoU-fXwZo6x3z7IbSaSNwS0P-50qeV99Mc0AUSIvB26GjmjZ2gEH5R3YD9kp0DOrYvE5tIymVHPTqkmunv2OrjKu2UOhNj8Om3RoVzxIkVM89cVGb1u1yB2kxEmXogXPz64cKqQWm22tV-jalS4dAc_1p9A9sKzZ632HxnlavOBjTKDGFgM95gg8M5npXBP3QIvkwW3yervCukViRUKIm-ljpDmnBJsZTMx0uzTaAk5XgoCUCADuLLol8EXB-0V4m2w-6tV6kAzRiwkqw1PRrGqplf-gmfU7TuFlQ142-EZLU5rK_dAiQRXx-f7LxNH", )" + R"( "fileUrls": { )" + R"( "f483750ebb885d32c": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/e5cc19d5e9174c93ada35cc315f1fb1d/apt-manifest-tree-1.0.json", )" + R"( "f222b9ffefaaac577": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/31c38c3340a84e38ae8d30ce340f4a49/contoso.contoso-virtual-motors.1.1.updatemanifest.json", )" + R"( "f2c5d1f3b0295db0f": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/9ff068f7c2bf43eb9561da14a7cbcecd/motor-firmware-1.1.json", )" + R"( "f13b5435aab7c18da": "http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/c02058a476a242d7bc0e3c576c180051/contoso-motor-installscript.sh" )" + R"( } )" + R"( } )"; // clang-format on @@ -620,28 +623,53 @@ TEST_CASE("workflow_isequal_id") workflow_free(handle0); } -TEST_CASE("result success erc") +TEST_CASE("result additonal erc") { - SECTION("Not set is zero") + SECTION("None") + { + ADUC_WorkflowHandle h = nullptr; + + ADUC_Result result = workflow_init(manifest_workflow_id_compare_0, false /* validateManifest */, &h); + REQUIRE(result.ResultCode == ADUC_Result_Success); + + STRING_HANDLE extra_erc_handle = workflow_get_extra_ercs(h); + CHECK(extra_erc_handle != nullptr); + + ADUC::StringUtils::STRING_HANDLE_wrapper extra_erc{ extra_erc_handle }; + CHECK_THAT(STRING_c_str(extra_erc.get()), Equals("")); + } + + SECTION("add and get") { ADUC_WorkflowHandle h = nullptr; ADUC_Result result = workflow_init(manifest_workflow_id_compare_0, false /* validateManifest */, &h); REQUIRE(result.ResultCode == ADUC_Result_Success); - ADUC_Result_t erc = workflow_get_success_erc(h); - CHECK(erc == 0); + workflow_add_erc(h, ADUC_ERC_NOMEM); + + STRING_HANDLE extra_erc_handle = workflow_get_extra_ercs(h); + REQUIRE(extra_erc_handle != nullptr); + + ADUC::StringUtils::STRING_HANDLE_wrapper extra_erc{ extra_erc_handle }; + CHECK_THAT(STRING_c_str(extra_erc_handle), Equals(",0000000C")); } - SECTION("set and get") + + SECTION("add 2 and get") { ADUC_WorkflowHandle h = nullptr; ADUC_Result result = workflow_init(manifest_workflow_id_compare_0, false /* validateManifest */, &h); REQUIRE(result.ResultCode == ADUC_Result_Success); - workflow_set_success_erc(h, ADUC_ERC_NOMEM); - ADUC_Result_t erc = workflow_get_success_erc(h); - CHECK(erc == ADUC_ERC_NOMEM); + workflow_add_erc(h, ADUC_ERC_NOMEM); + workflow_add_erc(h, ADUC_ERC_UTILITIES_ROOTKEYPKG_DOWNLOAD_URL_BAD_PATH); + + STRING_HANDLE extra_erc_handle = workflow_get_extra_ercs(h); + REQUIRE(extra_erc_handle != nullptr); + + ADUC::StringUtils::STRING_HANDLE_wrapper extra_erc{ extra_erc_handle }; + CHECK_THAT(STRING_c_str(extra_erc_handle), Equals(",0000000C,8050001F")); } }