├── .github ├── .cSpellWords.txt ├── CODEOWNERS ├── CONTRIBUTING.md ├── links_allowlist.txt ├── memory_statistics_config.json ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── doxygen.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── MISRA.md ├── README.md ├── SECURITY.md ├── cspell.config.yaml ├── docs ├── doxygen │ ├── config.doxyfile │ ├── include │ │ └── size_table.md │ ├── layout.xml │ ├── pages.dox │ ├── porting.dox │ └── style.css └── plantuml │ ├── images │ └── sigv4_design.png │ └── sigv4_design.pu ├── manifest.yml ├── sigv4FilePaths.cmake ├── source ├── include │ ├── sigv4.h │ ├── sigv4_config_defaults.h │ ├── sigv4_internal.h │ └── sigv4_quicksort.h ├── sigv4.c └── sigv4_quicksort.c ├── test ├── CMakeLists.txt ├── cbmc │ ├── .gitignore │ ├── include │ │ ├── README.md │ │ ├── hash_stubs.h │ │ ├── sigv4_annex.h │ │ ├── sigv4_config.h │ │ └── sigv4_stubs.h │ ├── proofs │ │ ├── Makefile-json.common │ │ ├── Makefile-project-defines │ │ ├── Makefile-project-targets │ │ ├── Makefile-project-testing │ │ ├── Makefile-template-defines │ │ ├── Makefile.common │ │ ├── README.md │ │ ├── SigV4_AwsIotDateToIso8601 │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── SigV4_AwsIotDateToIso8601_harness.c │ │ │ ├── cbmc-proof.txt │ │ │ └── cbmc-viewer.json │ │ ├── SigV4_GenerateHTTPAuthorization │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── SigV4_GenerateHTTPAuthorization_harness.c │ │ │ ├── cbmc-proof.txt │ │ │ └── cbmc-viewer.json │ │ ├── copyHeaderStringToCanonicalBuffer │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── cbmc-proof.txt │ │ │ ├── cbmc-viewer.json │ │ │ └── copyHeaderStringToCanonicalBuffer_harness.c │ │ ├── lib │ │ │ ├── __init__.py │ │ │ ├── print_tool_versions.py │ │ │ └── summarize.py │ │ └── run-cbmc-proofs.py │ ├── sources │ │ └── README.md │ └── stubs │ │ ├── README.md │ │ ├── hash_stubs.c │ │ ├── memcpy.c │ │ ├── memmove.c │ │ └── sigv4_stubs.c ├── include │ └── sigv4_config.h └── unit-test │ ├── CMakeLists.txt │ ├── cmock_build.cmake │ ├── sigv4_config.h │ └── sigv4_utest.c └── tools ├── cmock ├── coverage.cmake ├── create_test.cmake └── project.yml └── coverity ├── README.md └── misra.config /.github/.cSpellWords.txt: -------------------------------------------------------------------------------- 1 | Aizca 2 | AKIAIOSFODNN 3 | Ayjrf 4 | Bgza 5 | cbmc 6 | CBMC 7 | cbor 8 | CBOR 9 | chjdsvchjdvhjcdhjsckhdsvchdks 10 | cmock 11 | Cmock 12 | CMock 13 | CMOCK 14 | Cnpb 15 | Cnpbfi 16 | coremqtt 17 | coverity 18 | Coverity 19 | CSDK 20 | ctest 21 | Cuiz 22 | DCMOCK 23 | DDISABLE 24 | decihours 25 | Decihours 26 | DECIHOURS 27 | DNDEBUG 28 | DSIGV 29 | DUNITY 30 | DUNITTEST 31 | Ecjuve 32 | EKHX 33 | getpacketid 34 | GGHU 35 | Gicnak 36 | gjfhjxgxghsgfdwfdfdfdffhfdhdhfhdfhd 37 | HMDL 38 | Hpxdr 39 | isystem 40 | Kcdef 41 | Kced 42 | lcov 43 | Lkec 44 | misra 45 | Misra 46 | MISRA 47 | mlkzxncvlknlkanlkqwlerknlasdflkzxcnvklnlksqwerasdfklqwenrklnfsad 48 | MQTT 49 | mypy 50 | Ndzbbpmap 51 | NGYY 52 | nondet 53 | Nondet 54 | NONDET 55 | opad 56 | OPAD 57 | pasdfghwsshasdfghjk 58 | Pjiyp 59 | Pnpyim 60 | pylint 61 | pytest 62 | pyyaml 63 | Qvpwa 64 | Qwxh 65 | Rajbw 66 | reall 67 | sdgfdfgdshfgsjdhfdhfkhdkfhjdgfgdfgdfg 68 | sdvfdvfhdvfhvdhfvdsfdsgfgdsjfgjdsfqwertyuio 69 | sfdghfdfahgsdhfgjsgfjkgfsdgkdgfdjkgdggdjfsjkgjksgkj 70 | sigv 71 | SIGV 72 | sinclude 73 | Sutzy 74 | Thwgv 75 | Uijcfxv 76 | UNACKED 77 | unpadded 78 | Unpadded 79 | UNPADDED 80 | UNSUB 81 | UNSUBACK 82 | unsubscriptions 83 | utest 84 | Vajgc 85 | vect 86 | Vect 87 | VECT 88 | Vwng 89 | wnqj 90 | Wunused 91 | xchjsd 92 | XLFAUQG 93 | ymxchykldfghiwbdcjhjdddkkgddsdhshdkshdhsskgfkjgfggc 94 | YYYYMMDD'T'HHMMSS'Z' 95 | Zapv 96 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Each line is a file pattern followed by one or more owners. 2 | 3 | # These owners will be the default owners for everything in 4 | # the repo. Unless a later match takes precedence, 5 | # @global-owner1 and @global-owner2 will be requested for 6 | # review when someone opens a pull request. 7 | * @aws/freertos-pr-bar-raisers 8 | 9 | # Order is important; the last matching pattern takes the most 10 | # precedence. When someone opens a pull request that only 11 | # modifies c files, only @FreeRTOS/pr-bar-raiser and not the 12 | # global owner(s) will be requested for a review. 13 | # *.c FreeRTOS/pr-bar-raiser 14 | 15 | # You can also use email addresses if you prefer. They'll be 16 | # used to look up users just like we do for commit author 17 | # emails. 18 | # *.go docs@example.com 19 | 20 | # In this example, @doctocat owns any files in the build/logs 21 | # directory at the root of the repository and any of its 22 | # subdirectories. 23 | # /build/logs/ @doctocat 24 | 25 | # The `docs/*` pattern will match files like 26 | # `docs/getting-started.md` but not further nested files like 27 | # `docs/build-app/troubleshooting.md`. 28 | # docs/* docs@example.com 29 | 30 | # In this example, @octocat owns any file in an apps directory 31 | # anywhere in your repository. 32 | # apps/ @octocat 33 | 34 | # In this example, @doctocat owns any file in the `/docs` 35 | # directory in the root of your repository and any of its 36 | # subdirectories. 37 | # /docs/ @doctocat -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/issues), or [recently closed](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/issues?q=is%3Aissue+is%3Aclosed) issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 1. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 1. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 1. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 1. Ensure that your contributions conform to the [style guide](https://docs.aws.amazon.com/embedded-csdk/202011.00/lib-ref/docs/doxygen/output/html/guide_developer_styleguide.html). 35 | 1. Format your code with uncrustify, using the config available in [FreeRTOS/CI-CD-Github-Actions](https://github.com/FreeRTOS/CI-CD-Github-Actions/blob/main/formatting/uncrustify.cfg). 36 | 1. Ensure local tests pass. 37 | 1. Commit to your fork using clear commit messages. 38 | 1. Send us a pull request, answering any default questions in the pull request interface. 39 | 1. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 40 | 41 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 42 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 43 | 44 | 45 | ## Finding contributions to work on 46 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/labels?q=help+wanted) issues is a great place to start. 47 | 48 | 49 | ## Code of Conduct 50 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 51 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 52 | opensource-codeofconduct@amazon.com with any additional questions or comments. 53 | 54 | 55 | ## Security issue notifications 56 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](https://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public Github issue. 57 | 58 | 59 | ## Licensing 60 | 61 | See the [LICENSE](../LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 62 | 63 | We may ask you to sign a [Contributor License Agreement (CLA)](https://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 64 | -------------------------------------------------------------------------------- /.github/links_allowlist.txt: -------------------------------------------------------------------------------- 1 | https://www.somewebsite.com/path/to/item.txt?optionalquery=stuff 2 | -------------------------------------------------------------------------------- /.github/memory_statistics_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib_name": "AWS SigV4 library", 3 | "src": [ 4 | "source/sigv4.c", 5 | "source/sigv4_quicksort.c" 6 | ], 7 | "include": [ 8 | "source/include" 9 | ], 10 | "compiler_flags": [ 11 | "SIGV4_DO_NOT_USE_CUSTOM_CONFIG" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Description 4 | ----------- 5 | 6 | 7 | Test Steps 8 | ----------- 9 | 10 | 11 | Checklist: 12 | ---------- 13 | 14 | 15 | - [ ] I have tested my changes. No regression in existing tests. 16 | - [ ] I have modified and/or added unit-tests to cover the code changes in this Pull Request. 17 | 18 | Related Issue 19 | ----------- 20 | 21 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 22 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI Checks 2 | 3 | on: 4 | push: 5 | branches: ["**"] 6 | pull_request: 7 | branches: [main] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build-check-library: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Clone This Repo 15 | uses: actions/checkout@v3 16 | 17 | - name: Build in Release Mode 18 | run: | 19 | cmake -S test -B build/ \ 20 | -G "Unix Makefiles" \ 21 | -DCMAKE_BUILD_TYPE=Debug \ 22 | -DCMAKE_C_FLAGS='-Wall -Wextra -Werror' 23 | make -C build/ all 24 | 25 | unittest: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Clone This Repo 29 | uses: actions/checkout@v3 30 | 31 | - name: Build 32 | run: | 33 | sudo apt-get install -y lcov 34 | cmake -S test -B build/ \ 35 | -G "Unix Makefiles" \ 36 | -DCMAKE_BUILD_TYPE=Debug \ 37 | -DUNITTEST=ON \ 38 | -DCMAKE_C_FLAGS='--coverage -Wall -Wextra -DNDEBUG' 39 | make -C build/ all 40 | 41 | - name: Test 42 | run: | 43 | cd build/ 44 | ctest -E system --output-on-failure 45 | cd .. 46 | 47 | - name: Run Coverage 48 | run: | 49 | make -C build/ coverage 50 | declare -a EXCLUDE=("\*test\*" "\*CMakeCCompilerId.c") 51 | echo ${EXCLUDE[@]} | xargs lcov --rc branch_coverage=1 --ignore-errors empty --ignore-errors source -r build/coverage.info -o build/coverage.info 52 | lcov --rc branch_coverage=1 --ignore-errors empty --ignore-errors source --list build/coverage.info 53 | 54 | - name: Check Coverage 55 | uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main 56 | with: 57 | coverage-file: ./build/coverage.info 58 | 59 | build-with-default-config: 60 | runs-on: ubuntu-latest 61 | steps: 62 | - name: Clone This Repo 63 | uses: actions/checkout@v3 64 | 65 | - name: Build 66 | run: | 67 | cmake -S test -B build/ \ 68 | -G "Unix Makefiles" \ 69 | -DCMAKE_BUILD_TYPE=Debug \ 70 | -DCMAKE_C_FLAGS='-Wall -Wextra -Werror -DSIGV4_DO_NOT_USE_CUSTOM_CONFIG' 71 | make -C build/ all 72 | 73 | complexity: 74 | runs-on: ubuntu-latest 75 | steps: 76 | - uses: actions/checkout@v3 77 | 78 | - name: Check complexity 79 | uses: FreeRTOS/CI-CD-Github-Actions/complexity@main 80 | with: 81 | path: ./ 82 | 83 | doxygen: 84 | runs-on: ubuntu-latest 85 | steps: 86 | - uses: actions/checkout@v3 87 | 88 | - name: Run doxygen build 89 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen@main 90 | with: 91 | path: ./ 92 | 93 | spell-check: 94 | runs-on: ubuntu-latest 95 | steps: 96 | 97 | - name: Clone This Repo 98 | uses: actions/checkout@v3 99 | 100 | - name: Run spellings check 101 | uses: FreeRTOS/CI-CD-Github-Actions/spellings@main 102 | with: 103 | path: ./ 104 | 105 | formatting: 106 | runs-on: ubuntu-latest 107 | steps: 108 | - uses: actions/checkout@v3 109 | 110 | - name: Check formatting 111 | uses: FreeRTOS/CI-CD-Github-Actions/formatting@main 112 | with: 113 | path: ./ 114 | 115 | git-secrets: 116 | runs-on: ubuntu-latest 117 | steps: 118 | - uses: actions/checkout@v3 119 | 120 | - name: Checkout awslabs/git-secrets 121 | uses: actions/checkout@v3 122 | with: 123 | repository: awslabs/git-secrets 124 | ref: master 125 | path: git-secrets 126 | 127 | - name: Install git-secrets 128 | run: cd git-secrets && sudo make install && cd .. 129 | 130 | - name: Run git-secrets 131 | run: | 132 | git-secrets --register-aws 133 | git-secrets --scan 134 | 135 | memory_statistics: 136 | runs-on: ubuntu-latest 137 | steps: 138 | - uses: actions/checkout@v3 139 | with: 140 | submodules: "recursive" 141 | 142 | - name: Install Python3 143 | uses: actions/setup-python@v3 144 | with: 145 | python-version: "3.11.0" 146 | 147 | - name: Measure sizes 148 | uses: FreeRTOS/CI-CD-Github-Actions/memory_statistics@main 149 | with: 150 | config: .github/memory_statistics_config.json 151 | check_against: docs/doxygen/include/size_table.md 152 | 153 | link-verifier: 154 | runs-on: ubuntu-latest 155 | steps: 156 | - uses: actions/checkout@v3 157 | - name: Check Links 158 | env: 159 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 160 | uses: FreeRTOS/CI-CD-Github-Actions/link-verifier@main 161 | 162 | verify-manifest: 163 | runs-on: ubuntu-latest 164 | steps: 165 | - uses: actions/checkout@v3 166 | with: 167 | submodules: true 168 | fetch-depth: 0 169 | 170 | # At time of writing the gitmodules are set not to pull 171 | # Even when using fetch submodules. Need to run this command 172 | # To force it to grab them. 173 | - name: Perform Recursive Clone 174 | shell: bash 175 | run: git submodule update --checkout --init --recursive 176 | 177 | - name: Run manifest verifier 178 | uses: FreeRTOS/CI-CD-GitHub-Actions/manifest-verifier@main 179 | with: 180 | path: ./ 181 | fail-on-incorrect-version: true 182 | 183 | proof_ci: 184 | if: ${{ github.event.pull_request }} 185 | runs-on: cbmc_ubuntu-latest_32-core 186 | steps: 187 | - name: Set up CBMC runner 188 | uses: FreeRTOS/CI-CD-Github-Actions/set_up_cbmc_runner@main 189 | with: 190 | cbmc_version: "6.1.1" 191 | 192 | - name: Run CBMC 193 | uses: FreeRTOS/CI-CD-Github-Actions/run_cbmc@main 194 | with: 195 | proofs_dir: test/cbmc/proofs 196 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen Generation 2 | on: 3 | push: 4 | branches: [main] 5 | workflow_dispatch: 6 | jobs: 7 | doxygen-generation: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Doxygen generation 11 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release automation 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | commit_id: 7 | description: 'Commit ID to tag and create a release for' 8 | required: true 9 | version_number: 10 | description: 'Release Version Number (Eg, v1.0.0)' 11 | required: true 12 | 13 | jobs: 14 | tag-commit: 15 | name: Generate SBOM and tag commit 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v4 20 | with: 21 | ref: ${{ github.event.inputs.commit_id }} 22 | - name: Configure git identity 23 | run: | 24 | git config --global user.name ${{ github.actor }} 25 | git config --global user.email ${{ github.actor }}@users.noreply.github.com 26 | - name: create a new branch that references commit id 27 | run: git checkout -b ${{ github.event.inputs.version_number }} ${{ github.event.inputs.commit_id }} 28 | - name: Generate SBOM 29 | uses: FreeRTOS/CI-CD-Github-Actions/sbom-generator@main 30 | with: 31 | repo_path: ./ 32 | source_path: ./source 33 | - name: commit SBOM file 34 | run: | 35 | git add . 36 | git commit -m 'Update SBOM' 37 | git push -u origin ${{ github.event.inputs.version_number }} 38 | - name: Tag Commit and Push to remote 39 | run: | 40 | git tag ${{ github.event.inputs.version_number }} -a -m "AWS IoT SigV4 ${{ github.event.inputs.version_number }}" 41 | git push origin --tags 42 | - name: Verify tag on remote 43 | run: | 44 | git tag -d ${{ github.event.inputs.version_number }} 45 | git remote update 46 | git checkout tags/${{ github.event.inputs.version_number }} 47 | git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }} 48 | create-zip: 49 | needs: tag-commit 50 | name: Create ZIP and verify package for release asset. 51 | runs-on: ubuntu-latest 52 | steps: 53 | - name: Install ZIP tools 54 | run: sudo apt-get install zip unzip 55 | - name: Checkout code 56 | uses: actions/checkout@v4 57 | with: 58 | ref: ${{ github.event.inputs.commit_id }} 59 | path: SigV4-for-AWS-IoT-embedded-sdk 60 | submodules: recursive 61 | - name: Checkout disabled submodules 62 | run: | 63 | cd SigV4-for-AWS-IoT-embedded-sdk 64 | git submodule update --init --checkout --recursive 65 | - name: Create ZIP 66 | run: | 67 | zip -r SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip SigV4-for-AWS-IoT-embedded-sdk -x "*.git*" 68 | ls ./ 69 | - name: Validate created ZIP 70 | run: | 71 | mkdir zip-check 72 | mv SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip zip-check 73 | cd zip-check 74 | unzip SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip -d SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }} 75 | ls SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }} 76 | diff -r -x "*.git*" SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/SigV4-for-AWS-IoT-embedded-sdk/ ../SigV4-for-AWS-IoT-embedded-sdk/ 77 | cd ../ 78 | - name: Build 79 | run: | 80 | cd zip-check/SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/SigV4-for-AWS-IoT-embedded-sdk 81 | sudo apt-get install -y lcov 82 | cmake -S test -B build/ \ 83 | -G "Unix Makefiles" \ 84 | -DCMAKE_BUILD_TYPE=Debug \ 85 | -DBUILD_CLONE_SUBMODULES=ON \ 86 | -DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG' 87 | make -C build/ all 88 | - name: Test 89 | run: | 90 | cd zip-check/SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/SigV4-for-AWS-IoT-embedded-sdk/build/ 91 | ctest -E system --output-on-failure 92 | cd .. 93 | - name: Create artifact of ZIP 94 | uses: actions/upload-artifact@v4 95 | with: 96 | name: SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip 97 | path: zip-check/SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip 98 | deploy-doxygen: 99 | needs: tag-commit 100 | name: Deploy doxygen documentation 101 | runs-on: ubuntu-latest 102 | steps: 103 | - name: Doxygen generation 104 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main 105 | with: 106 | ref: ${{ github.event.inputs.version_number }} 107 | add_release: "true" 108 | create-release: 109 | needs: 110 | - create-zip 111 | - deploy-doxygen 112 | name: Create Release and Upload Release Asset 113 | runs-on: ubuntu-latest 114 | steps: 115 | - name: Create Release 116 | id: create_release 117 | uses: actions/create-release@v1 118 | env: 119 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 120 | with: 121 | tag_name: ${{ github.event.inputs.version_number }} 122 | release_name: ${{ github.event.inputs.version_number }} 123 | body: Release ${{ github.event.inputs.version_number }} of AWS IoT SigV4. 124 | draft: false 125 | prerelease: false 126 | - name: Download ZIP artifact 127 | uses: actions/download-artifact@v4 128 | with: 129 | name: SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip 130 | - name: Upload Release Asset 131 | id: upload-release-asset 132 | uses: actions/upload-release-asset@v1 133 | env: 134 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 135 | with: 136 | upload_url: ${{ steps.create_release.outputs.upload_url }} 137 | asset_path: ./SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip 138 | asset_name: SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip 139 | asset_content_type: application/zip 140 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore documentation output. 2 | **/docs/**/output/* 3 | 4 | # Ignore CMake build directory. 5 | build/ 6 | 7 | # Ignore build artifacts. 8 | *.o 9 | 10 | # Ignore code coverage artifacts. 11 | *.gcda 12 | *.gcno 13 | *.gcov 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/unit-test/CMock"] 2 | path = test/unit-test/CMock 3 | url = https://github.com/ThrowTheSwitch/CMock.git 4 | update = none 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog for AWS SigV4 Library 2 | 3 | ## v1.3.0 (May 2024) 4 | 5 | - [#93](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/93) Update CanonicalContext structure for MISRA compliance 6 | - [#92](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/92) MISRA C:2012 Compliance Update 7 | - [#89](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/89) Support presigned URL signature "UNSIGNED-PAYLOAD" and expose EncodeURI 8 | - [#85](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/85) Fix bugs in generating canonical Query 9 | - [#77](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/77) Update Doxygen version to 1.9.6 10 | 11 | ## v1.2.0 (October 2022) 12 | 13 | - [#71](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/71) MISRA C:2012 Compliance Update 14 | - [#70](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/70) Update CBMC starter kit 15 | 16 | ## v1.1.0 (December 2021) 17 | 18 | - [#63](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/63) Remove extraneous parentheses in isAllowedChar() 19 | - [#62](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/62) Enable logging macros in CI checks for SigV4 20 | - [#59](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/59) Remove superfluous memmove 21 | - [#58](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/58) Utility word removal from Sigv4 Library 22 | - [#57](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/57) SigV4 Porting Guide 23 | - [#56](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/56) Update Doxygen version to 1.9.2 24 | - [#55](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/55) CBMC Proof Failure Fixes 25 | - [#52](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/52) Fix bugs in generating canonical Query and improve functionality coverage in unit tests. 26 | - [#51](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/51) Payload hash optimization 27 | 28 | ## v1.0.0 (August 2021) 29 | 30 | This is the first release of the AWS SigV4 Library. 31 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project information. 2 | cmake_minimum_required( VERSION 3.10.0 ) 3 | project( "sigv4" LANGUAGES C ) 4 | 5 | # Allow the project to be organized into folders. 6 | set_property( GLOBAL PROPERTY USE_FOLDERS ON ) 7 | 8 | set( CMAKE_C_STANDARD_REQUIRED ON ) 9 | 10 | # Do not allow in-source build. 11 | if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} ) 12 | message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." ) 13 | endif() 14 | 15 | # Set global path variables. 16 | get_filename_component( __MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE ) 17 | set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "SigV4 repository root." ) 18 | 19 | 20 | # Set output directories. 21 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) 22 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 23 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 24 | 25 | 26 | # Include filepaths for source and include. 27 | include( ${MODULE_ROOT_DIR}/sigv4FilePaths.cmake ) 28 | 29 | add_library(${PROJECT_NAME}) 30 | target_sources(${PROJECT_NAME} PRIVATE ${SIGV4_SOURCES}) 31 | target_include_directories(${PROJECT_NAME} PUBLIC 32 | $ 33 | $ 34 | ) 35 | 36 | # `sigv4_config` target defines the path to sigv4_config.h and optionally other based config files 37 | if( NOT TARGET sigv4_config ) 38 | target_compile_definitions(${PROJECT_NAME} PRIVATE -DSIGV4_DO_NOT_USE_CUSTOM_CONFIG ) 39 | endif() 40 | 41 | include( GNUInstallDirs ) 42 | 43 | install( TARGETS ${PROJECT_NAME} 44 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME} 45 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} 46 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME} 47 | ) 48 | 49 | install( DIRECTORY ${SIGV4_INCLUDE_PUBLIC_DIRS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} ) 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /MISRA.md: -------------------------------------------------------------------------------- 1 | # MISRA Compliance 2 | 3 | The AWS SigV4 Library files conform to the [MISRA C:2012](https://www.misra.org.uk) 4 | guidelines, with some noted exceptions. Compliance is checked with Coverity static analysis. 5 | The specific deviations, suppressed inline, are listed below. 6 | 7 | Additionally, [MISRA configuration file](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/blob/main/tools/coverity/misra.config) contains the project wide deviations. 8 | 9 | ### Suppressed with Coverity Comments 10 | To find the deviation references in the source files run grep on the source code 11 | with ( Assuming rule 5.4 violation; with justification in point 1 ): 12 | ``` 13 | grep 'MISRA Ref 5.4.1' . -rI 14 | ``` 15 | 16 | #### Rule 5.4 17 | _Ref 5.4.1_ 18 | 19 | - MISRA Rule 5.4 flags the following macro's name as ambiguous from the 20 | one postfixed with _LENGTH. The macro highlighted by the deviation is already 21 | in use and changing the name will break existing user projects. Thus, for 22 | backwards compatibility, the macro is not modified and kept as is and the 23 | deviation is suppressed. 24 | 25 | _Ref 18.2.1_ 26 | 27 | - MISRA Rule 18.2 states that two pointers may only be subtracted if they point 28 | to elements of the same array. In this library, array of bytes are used to process 29 | data. Functions which fill the arrays with data update an index to an offset. 30 | To know the amount of data added to the array, the beginning address of the array has 31 | to be subtracted from the index. It is manually verified that the index will always be 32 | within bounds of the array. However, Coverity is flagging this as a deviation. Thus, we 33 | are suppressing it. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS SigV4 Library 2 | 3 | **[API Documentation Pages for current and previous releases of this library can be found here](https://aws.github.io/SigV4-for-AWS-IoT-embedded-sdk/)** 4 | 5 | The AWS SigV4 Library is a standalone library for generating authorization 6 | headers and signatures according to the specifications of the 7 | [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) 8 | signing process. Authorization headers are required for authentication when 9 | sending HTTP requests to AWS. This library can optionally be used by 10 | applications sending direct HTTP requests to AWS services requiring SigV4 11 | authentication. This library has no dependencies on any additional libraries 12 | other than the standard C library. This library is distributed under the MIT 13 | Open Source License. 14 | 15 | This library has gone through code quality checks including verification that no 16 | function has a GNU Complexity score over 8, and checks against deviations from 17 | mandatory rules in the MISRA coding standard. Deviations from the MISRA C:2012 18 | guidelines are documented under MISRA Deviations. This library has also 19 | undergone static code analysis using Coverity static analysis, and validation of 20 | memory safety through the CBMC automated reasoning tool. 21 | 22 | See memory requirements for this library [here][memory_table]. 23 | 24 | [memory_table]: ./docs/doxygen/include/size_table.md 25 | 26 | **AWS SigV4 v1.3.0 27 | [source code](https://github.com/aws/Sigv4-for-AWS-IoT-embedded-sdk/tree/v1.3.0/source) 28 | is part of the 29 | [FreeRTOS 202406.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202406.00-LTS) 30 | release.** 31 | 32 | ## AWS SigV4 Library Config File 33 | 34 | The AWS SigV4 library exposes build configuration macros that are required for 35 | building the library. A list of all the configurations and their default values 36 | are defined in [sigv4_config_defaults.h][default_config]. To provide custom 37 | values for the configuration macros, a config file named `sigv4_config.h` can be 38 | provided by the application to the library. 39 | 40 | [default_config]: source/include/sigv4_config_defaults.h 41 | 42 | By default, a `sigv4_config.h` config file is required to build the library. To 43 | disable this requirement and build the library with default configuration 44 | values, provide `SIGV4_DO_NOT_USE_CUSTOM_CONFIG` as a compile time preprocessor 45 | macro. 46 | 47 | **Thus, the SigV4 library can be built by either**: 48 | 49 | - Defining a `sigv4_config.h` file in the application, and adding it to the 50 | include directories list of the library. 51 | 52 | **OR** 53 | 54 | - Defining the `SIGV4_DO_NOT_USE_CUSTOM_CONFIG` preprocessor macro for the 55 | library build. 56 | 57 | ## Building the SigV4 Library 58 | 59 | The [sigv4FilePaths.cmake](sigv4FilePaths.cmake) file contains information of 60 | all the source files and header include paths required to build the SigV4 61 | library. 62 | 63 | As mentioned in the previous section, either a custom config file (i.e. 64 | `sigv4_config.h`) or `SIGV4_DO_NOT_USE_CUSTOM_CONFIG` macro needs to be provided 65 | to build the SigV4 library. 66 | 67 | To use CMake, please refer to the 68 | [sigV4FilePaths.cmake](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/blob/main/sigv4FilePaths.cmake) 69 | file, which contains the relevant information regarding source files and header 70 | include paths required to build this library. 71 | 72 | ## Building Unit Tests 73 | 74 | ### Platform Prerequisites 75 | 76 | - For running unit tests: 77 | - **C90 compiler** like gcc. 78 | - **CMake 3.13.0 or later**. 79 | - **Ruby 2.0.0 or later** is additionally required for the CMock test 80 | framework (that we use). 81 | - For running the coverage target, **gcov** and **lcov** are additionally 82 | required. 83 | 84 | ### Steps to build **Unit Tests** 85 | 86 | 1. Go to the root directory of this repository. 87 | 88 | 1. Run the _cmake_ command: `cmake -S test -B build -DUNITTEST=ON`. 89 | 90 | 1. Run this command to build the library and unit tests: `make -C build all`. 91 | 92 | 1. The generated test executables will be present in `build/bin/tests` folder. 93 | 94 | 1. Run `cd build && ctest` to execute all tests and view the test run summary. 95 | 96 | ## CBMC 97 | 98 | To learn more about CBMC and proofs specifically, review the training material 99 | [here](https://model-checking.github.io/cbmc-training). 100 | 101 | The `test/cbmc/proofs` directory contains CBMC proofs. 102 | 103 | In order to run these proofs you will need to install CBMC and other tools by 104 | following the instructions 105 | [here](https://model-checking.github.io/cbmc-training/installation.html). 106 | 107 | ## Reference examples 108 | 109 | The AWS IoT Embedded C-SDK repository contains 110 | [HTTP demos](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/main/demos/http) 111 | showing the use of the AWS SigV4 Library on a POSIX platform to authenticate 112 | HTTP requests to AWS S3 service. 113 | 114 | ## Generating documentation 115 | 116 | The Doxygen references found in this repository were created using Doxygen 117 | version 1.9.6. To generate these Doxygen pages, please run the following command 118 | from the root of this repository: 119 | 120 | ```shell 121 | doxygen docs/doxygen/config.doxyfile 122 | ``` 123 | 124 | ## Contributing 125 | 126 | See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for information on contributing. 127 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Reporting a Vulnerability 2 | 3 | If you discover a potential security issue in this project, we ask that you notify AWS/Amazon Security 4 | via our [vulnerability reporting page](https://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com. 5 | Please do **not** create a public github issue. -------------------------------------------------------------------------------- /cspell.config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | $schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json 3 | version: '0.2' 4 | # Allows things like stringLength 5 | allowCompoundWords: true 6 | 7 | # Read files not to spell check from the git ignore 8 | useGitignore: true 9 | 10 | # Language settings for C 11 | languageSettings: 12 | - caseSensitive: false 13 | enabled: true 14 | languageId: c 15 | locale: "*" 16 | 17 | # Add a dictionary, and the path to the word list 18 | dictionaryDefinitions: 19 | - name: freertos-words 20 | path: '.github/.cSpellWords.txt' 21 | addWords: true 22 | 23 | dictionaries: 24 | - freertos-words 25 | 26 | # Paths and files to ignore 27 | ignorePaths: 28 | - 'dependency' 29 | - 'docs' 30 | - 'ThirdParty' 31 | - 'History.txt' 32 | -------------------------------------------------------------------------------- /docs/doxygen/include/size_table.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
Code Size of AWS SigV4 library (example generated with GCC for ARM Cortex-M)
File
With -O1 Optimization
With -Os Optimization
sigv4.c
5.4K
4.5K
sigv4_quicksort.c
0.4K
0.3K
Total estimates
5.8K
4.8K
26 | -------------------------------------------------------------------------------- /docs/doxygen/layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /docs/doxygen/pages.dox: -------------------------------------------------------------------------------- 1 | /** 2 | @mainpage Overview 3 | @anchor sigv4 4 | @brief AWS SigV4 Library 5 | 6 | The AWS SigV4 Library is a standalone library for generating signatures 7 | and authorization headers according to the specifications of the AWS Signature 8 | Version 4 signing process. This library aids applications in sending direct 9 | HTTP requests to AWS services requiring SigV4 authentication. The library is 10 | written in C and designed to be compliant with ISO C90 and MISRA C and has no 11 | dependencies on any additional libraries other than the standard C library. 12 | 13 | @section sigv4_memory_requirements Memory Requirements 14 | @brief Memory requirements of the SigV4 Library. 15 | 16 | @include{doc} size_table.md 17 | 18 | @section sigv4_design Design 19 | @brief SigV4 Library Design 20 | 21 |

Memory Usage

22 |

23 | All functions in the SigV4 library operate only on the buffers provided and use only 24 | local variables on the stack. 25 |

26 | 27 |

Compliance & Coverage

28 | 29 |

30 | The SIGV4 library is designed to be compliant with ISO C90 and MISRA C:2012. 31 | All functions are written to have low complexity scores. Unit tests and CBMC 32 | proofs are written to cover every path of execution and achieve 100% branch 33 | coverage. 34 |

35 | 36 | The diagram below demonstrates the happy path an application can take to use 37 | the SigV4 library to interact with AWS Services that support SigV4 authentication via HTTP requests. 38 | 39 | @image html sigv4_design.png "SigV4 Library Usage diagram" width=90% 40 | 41 | */ 42 | 43 | /** 44 | @page sigv4_config Configurations 45 | @brief Configurations of the AWS SigV4 Library. 46 | 48 | @par configpagestyle 49 | 50 | Configuration settings are C pre-processor constants. They can be set with a 51 | `\#define` in the config file (`sigv4_config.h`) or by using a 52 | compiler option such as -D in gcc. 53 | 54 | @section SIGV4_DO_NOT_USE_CUSTOM_CONFIG 55 | @copydoc SIGV4_DO_NOT_USE_CUSTOM_CONFIG 56 | 57 | @section sigv4_logerror LogError 58 | @copydoc LogError 59 | 60 | @section sigv4_logwarn LogWarn 61 | @copydoc LogWarn 62 | 63 | @section sigv4_loginfo LogInfo 64 | @copydoc LogInfo 65 | 66 | @section sigv4_logdebug LogDebug 67 | @copydoc LogDebug 68 | */ 69 | 70 | /** 71 | @page sigv4_functions Functions 72 | @brief Primary functions of the AWS SigV4 library:

73 | @subpage sigV4_generateHTTPAuthorization_function
74 | @subpage sigV4_awsIotDateToIso8601_function
75 | @subpage sigV4_encodeURI_function
76 | 77 | @page sigV4_generateHTTPAuthorization_function SigV4_GenerateHTTPAuthorization 78 | @snippet sigv4.h declare_sigV4_generateHTTPAuthorization_function 79 | @copydoc SigV4_GenerateHTTPAuthorization 80 | 81 | @page sigV4_awsIotDateToIso8601_function SigV4_AwsIotDateToIso8601 82 | @snippet sigv4.h declare_sigV4_awsIotDateToIso8601_function 83 | @copydoc SigV4_AwsIotDateToIso8601 84 | 85 | @page sigV4_encodeURI_function SigV4_EncodeURI 86 | @snippet sigv4.h declare_sigV4_encodeURI_function 87 | @copydoc SigV4_EncodeURI 88 | */ 89 | 90 | 91 | /** 92 | @defgroup sigv4_enum_types Enumerated Types 93 | @brief Enumerated types of the SigV4 library 94 | 95 | @defgroup sigv4_struct_types Struct Types 96 | @brief Struct types of the SigV4 library 97 | */ 98 | -------------------------------------------------------------------------------- /docs/doxygen/porting.dox: -------------------------------------------------------------------------------- 1 | /** 2 | * @page sigv4_porting Porting Guide 3 | * @brief Guide for porting the AWS SigV4 Library to a new 4 | * platform. 5 | * 6 | * To use the AWS SigV4 library, a platform must implement the following 7 | * components: 8 | * 1. [Configuration Macros](@ref sigv4_config_macros) 9 | * 2. [Crypto Interface](@ref sigv4_porting_cryptointerface) 10 | * 11 | * @section sigv4_config_macros Configuration Macros 12 | * @brief Configuration macros that can be set in the config header 13 | * `sigv4_config.h`, or passed in as compiler options. 14 | * 15 | * The following optional logging macros are used throughout the library: 16 | * - @ref LogError 17 | * - @ref LogWarn 18 | * - @ref LogInfo 19 | * - @ref LogDebug 20 | * 21 | * @see [Configurations](@ref sigv4_config) for more information. 22 | * 23 | * @note Regardless of whether the above macros are defined in 24 | * `sigv4_config.h` or passed as compiler options, by default the 25 | * `sigv4_config.h` file is needed to build the AWS SigV4 Library. To disable this requirement and build the library with 26 | * default configuration values, provide 27 | * `SIGV4_DO_NOT_USE_CUSTOM_CONFIG` as a compile time preprocessor 28 | * macro. 29 | * 30 | * @section sigv4_porting_cryptointerface Crypto Interface 31 | * @brief The AWS SigV4 library relies on the implementation of crypto interface 32 | * to provide hash functions used in generating the Authorization header by the library. 33 | * 34 | * A port must implement functions corresponding to the 35 | * following functions pointers: 36 | * - [Hash Initialize]: A function to initialize the Hash Context. 37 | * @code 38 | * int32_t ( * hashInit )( void * pHashContext ); 39 | * @endcode 40 | * - [Hash Update]: A function to update the hash to be calculated with more input data. 41 | * @code 42 | * int32_t ( * hashUpdate )( void * pHashContext, 43 | * const uint8_t * pInput, 44 | * size_t inputLen ); 45 | * @endcode 46 | * - [Hash Final]: A function to calculate the final binary digest of the hash from the context. 47 | * @code 48 | * int32_t ( * hashFinal )( void * pHashContext, 49 | * uint8_t * pOutput, 50 | * size_t outputLen ); 51 | * @endcode 52 | * 53 | * The above three functions take in a pointer to pHashContext which defines the context used 54 | * by the above function in calculating the hash. The HashContext must also be 55 | * defined by the user's implementation and ought to contain any information 56 | * necessary to calculate the hash. 57 | * @code 58 | * void * pHashContext; 59 | * @endcode 60 | * 61 | * A port must also define the following: 62 | * - [Hash Block Length]: The block length of the hash function implemented by the user. 63 | * @code 64 | * size_t hashBlockLen; 65 | * @endcode 66 | * 67 | * - [Hash Digest Length]: The digest length of the hash function implemented by the user. 68 | * @code 69 | * size_t hashDigestLen; 70 | * @endcode 71 | * 72 | */ 73 | -------------------------------------------------------------------------------- /docs/doxygen/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Stylesheet for Doxygen HTML output. 3 | * 4 | * This file defines styles for custom elements in the header/footer and 5 | * overrides some of the default Doxygen styles. 6 | * 7 | * Styles in this file do not affect the treeview sidebar. 8 | */ 9 | 10 | 11 | /* Set the margins to place a small amount of whitespace on the left and right 12 | * side of the page. */ 13 | div.contents { 14 | margin-left:4em; 15 | margin-right:4em; 16 | } 17 | 18 | 19 | /* Justify text in paragraphs. */ 20 | p { 21 | text-align: justify; 22 | } 23 | 24 | 25 | /* Style of section headings. */ 26 | h1 { 27 | border-bottom: 1px solid #879ECB; 28 | color: #354C7B; 29 | font-size: 160%; 30 | font-weight: normal; 31 | padding-bottom: 4px; 32 | padding-top: 8px; 33 | } 34 | 35 | 36 | /* Style of subsection headings. */ 37 | h2:not(.memtitle):not(.groupheader) { 38 | font-size: 125%; 39 | margin-bottom: 0px; 40 | margin-top: 16px; 41 | padding: 0px; 42 | } 43 | 44 | 45 | /* Style of paragraphs immediately after subsection headings. */ 46 | h2 + p { 47 | margin: 0px; 48 | padding: 0px; 49 | } 50 | 51 | 52 | /* Style of subsection headings. */ 53 | h3 { 54 | font-size: 100%; 55 | margin-bottom: 0px; 56 | margin-left: 2em; 57 | margin-right: 2em; 58 | } 59 | 60 | 61 | /* Style of paragraphs immediately after subsubsection headings. */ 62 | h3 + p { 63 | margin-top: 0px; 64 | margin-left: 2em; 65 | margin-right: 2em; 66 | } 67 | 68 | 69 | /* Style of the prefix "AWS IoT Device SDK C" that appears in the header. */ 70 | #csdkprefix { 71 | color: #757575; 72 | } 73 | 74 | 75 | /* Style of the "Return to main page" link that appears in the header. */ 76 | #returntomain { 77 | padding: 0.5em; 78 | } 79 | 80 | 81 | /* Style of the dividers on Configuration Settings pages. */ 82 | div.configpagedivider { 83 | margin-left: 0px !important; 84 | margin-right: 0px !important; 85 | margin-top: 20px !important; 86 | } 87 | 88 | 89 | /* Style of configuration setting names. */ 90 | dl.section.user ~ h1 { 91 | border-bottom: none; 92 | color: #000000; 93 | font-family: monospace, fixed; 94 | font-size: 16px; 95 | margin-bottom: 0px; 96 | margin-left: 2em; 97 | margin-top: 1.5em; 98 | } 99 | 100 | 101 | /* Style of paragraphs on a configuration settings page. */ 102 | dl.section.user ~ * { 103 | margin-bottom: 10px; 104 | margin-left: 4em; 105 | margin-right: 4em; 106 | margin-top: 0px; 107 | } 108 | 109 | 110 | /* Hide the configuration setting marker. */ 111 | dl.section.user { 112 | display: none; 113 | } 114 | 115 | 116 | /* Overrides for code fragments and lines. */ 117 | div.fragment { 118 | background: #ffffff; 119 | border: none; 120 | padding: 5px; 121 | } 122 | 123 | 124 | div.line { 125 | color: #3a3a3a; 126 | } 127 | 128 | 129 | /* Overrides for code syntax highlighting colors. */ 130 | span.comment { 131 | color: #008000; 132 | } 133 | 134 | 135 | span.keyword, span.keywordtype, span.keywordflow { 136 | color: #0000ff; 137 | } 138 | 139 | 140 | span.preprocessor { 141 | color: #50015a; 142 | } 143 | 144 | 145 | span.stringliteral, span.charliteral { 146 | color: #800c0c; 147 | } 148 | 149 | 150 | a.code, a.code:visited, a.line, a.line:visited { 151 | color: #496194; 152 | } 153 | -------------------------------------------------------------------------------- /docs/plantuml/images/sigv4_design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/SigV4-for-AWS-IoT-embedded-sdk/892bcbb2d4b95daf2b7306ba3210e74b25bfae16/docs/plantuml/images/sigv4_design.png -------------------------------------------------------------------------------- /docs/plantuml/sigv4_design.pu: -------------------------------------------------------------------------------- 1 | @startuml 2 | skinparam dpi 100 3 | skinparam classFontSize 8 4 | skinparam classFontName Helvetica 5 | autonumber 6 | 7 | box "Application" #LightGreen 8 | participant "Application" as application 9 | end box 10 | 11 | box "Library" #LightBlue 12 | participant "SigV4 Library" as sigv4 13 | end box 14 | 15 | box "IoT Server" #Yellow 16 | participant "IoT Server" as server 17 | end box 18 | 19 | box "AWS Server" #Orange 20 | participant "AWS Server" as aws 21 | end box 22 | activate application 23 | 24 | application -> server : Connect to AWS IOT Credential provider to fetch the temporary credentials 25 | server -> application : Connected and retrieved credentials 26 | 27 | application -> application: Parse the temporary credentials 28 | 29 | application -> server : Disconnect from server 30 | 31 | application -> application: Implement crypto interface hash functions. 32 | 33 | application -> sigv4 : Convert the AWS IoT date retrieved from AWS IoT Credential Provider\n to ISO8601 format using (SigV4_AwsIotDateToIso8601) API 34 | 35 | sigv4-> application : Date Converted and written to provided buffer 36 | 37 | application-> aws : Connect to AWS Server for sending the HTTP request 38 | 39 | aws->application : Connected 40 | 41 | application -> sigv4 : Generate Authorization header using (Sigv4_GenerateHTTPAuthorization) API 42 | 43 | 44 | application->application : Add the Authorization Header to the HTTP request to AWS Server. 45 | 46 | application-> aws : Send the HTTP request to AWS Server to perform the desired action 47 | 48 | aws-> application : Receive HTTP Response from AWS Server 49 | application -> aws: Disconnect from AWS server 50 | 51 | deactivate application 52 | @enduml 53 | 54 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | name : "SigV4-for-AWS-IoT-embedded-sdk" 2 | version: "v1.3.0" 3 | description: | 4 | "Library used in client authorization over HTTP with AWS IoT, on embedded devices.\n" 5 | license: "MIT" 6 | 7 | dependencies: 8 | - name: "CMock" 9 | version: v2.5.3 10 | license: "MIT" 11 | repository: 12 | type: "git" 13 | url: "https://github.com/ThrowTheSwitch/CMock.git" 14 | path: test/unit-test/CMock 15 | -------------------------------------------------------------------------------- /sigv4FilePaths.cmake: -------------------------------------------------------------------------------- 1 | # This file sets source files and include directories to variables so that they 2 | # can be reused from different repositories in their CMake based build system by 3 | # including this file. 4 | # 5 | # Files specific to the repository such as test runner and platform tests are 6 | # not added to the variables. 7 | 8 | # SigV4 library source files. 9 | set( SIGV4_SOURCES 10 | "${CMAKE_CURRENT_LIST_DIR}/source/sigv4.c" 11 | "${CMAKE_CURRENT_LIST_DIR}/source/sigv4_quicksort.c" ) 12 | 13 | # SigV4 library public include directories. 14 | set( SIGV4_INCLUDE_PUBLIC_DIRS 15 | "${CMAKE_CURRENT_LIST_DIR}/source/include" ) 16 | -------------------------------------------------------------------------------- /source/include/sigv4_config_defaults.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_config_defaults.h 27 | * @brief The default values for configuration macros used by the SigV4 Library. 28 | * 29 | * @note This file should NOT be modified. If custom values are needed for any 30 | * configuration macros, a sigv4_config.h file should be provided to the SigV4 31 | * Library to override the default values defined in this file. To use the custom 32 | * config file, the preprocessor macro SIGV4_DO_NOT_USE_CUSTOM_CONFIG 33 | * must NOT be set. 34 | */ 35 | 36 | #ifndef SIGV4_CONFIG_DEFAULTS_H_ 37 | #define SIGV4_CONFIG_DEFAULTS_H_ 38 | 39 | /* *INDENT-OFF* */ 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | /* *INDENT-ON* */ 44 | 45 | /* The macro definition for SIGV4_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen 46 | * documentation only. */ 47 | 48 | /** 49 | * @brief Define this macro to build the AWS IoT SigV4 Library without the 50 | * custom config file sigv4_config.h. 51 | * 52 | * Without the custom config, the the AWS IoT SigV4 Library builds with default 53 | * values of config macros defined in the sigv4_config_defaults.h file. 54 | * 55 | * If a custom config file is provided, then 56 | * SIGV4_DO_NOT_USE_CUSTOM_CONFIG must not be defined. 57 | * 58 | * Default value: SIGV4_DO_NOT_USE_CUSTOM_CONFIG is 59 | * not defined by default and the library expects a 60 | * sigv4_config.h file. 61 | */ 62 | #ifdef DOXYGEN 63 | #define SIGV4_DO_NOT_USE_CUSTOM_CONFIG 64 | #endif 65 | 66 | /** 67 | * @brief Macro defining the size of the internal buffer used for incremental 68 | * canonicalization and hashing. 69 | * 70 | * A buffer of this size in bytes is declared on the stack. It should be be 71 | * large enough for the digest output of the specified hash function. 72 | * 73 | * Possible values: Any positive 32 bit integer.
74 | * Default value: `1024` 75 | */ 76 | #ifndef SIGV4_PROCESSING_BUFFER_LENGTH 77 | #define SIGV4_PROCESSING_BUFFER_LENGTH 1024U 78 | #endif 79 | 80 | /** 81 | * @brief Macro defining the maximum number of headers in the request, used to 82 | * assist the library in sorting header fields during canonicalization. 83 | * 84 | * This macro should be updated if the number of request headers the application 85 | * wishes to sign is higher or lower than the default value (100). 86 | * 87 | * Possible values: Any positive 32 bit integer.
88 | * Default value: `100` 89 | */ 90 | #ifndef SIGV4_MAX_HTTP_HEADER_COUNT 91 | #define SIGV4_MAX_HTTP_HEADER_COUNT 100U 92 | #endif 93 | 94 | /** 95 | * @brief Macro defining the maximum number of query key/value pairs, used to 96 | * assist the library in sorting query keys during canonicalization. 97 | * 98 | * This macro should be updated if the number of query key/value pairs the 99 | * application wishes to sign is higher or lower than the default value (100). 100 | * 101 | * Possible values: Any positive 32 bit integer.
102 | * Default value: `100` 103 | */ 104 | #ifndef SIGV4_MAX_QUERY_PAIR_COUNT 105 | #define SIGV4_MAX_QUERY_PAIR_COUNT 100U 106 | #endif 107 | 108 | /** 109 | * @brief Macro used to compute the worst-case stack size when sorting elements 110 | * associated with #SIGV4_MAX_QUERY_PAIR_COUNT or #SIGV4_MAX_HTTP_HEADER_COUNT. 111 | * Suppose the max of the two aforementioned macros is X, then the macro 112 | * below must be set to 2 * ceiling(log(X)/log(2)) where ceiling rounds up 113 | * the ones digit if the decimal is greater than 0. 114 | * @note If updating #SIGV4_MAX_QUERY_PAIR_COUNT or #SIGV4_MAX_HTTP_HEADER_COUNT, 115 | * be sure to update this value based on the formula above. 116 | */ 117 | #ifndef SIGV4_WORST_CASE_SORT_STACK_SIZE 118 | #define SIGV4_WORST_CASE_SORT_STACK_SIZE 14U 119 | #endif 120 | 121 | /** 122 | * @brief Macro indicating the largest block size of any hashing 123 | * algorithm used for SigV4 authentication i.e. the maximum of all 124 | * values specified for the hashBlockLen in #SigV4CryptoInterface_t. 125 | * For example, using SHA-512 would require this value to be at least 128. 126 | * 127 | * Possible values: Any positive 32 bit integer.
128 | * Default value: `64` 129 | */ 130 | #ifndef SIGV4_HASH_MAX_BLOCK_LENGTH 131 | #define SIGV4_HASH_MAX_BLOCK_LENGTH 64U 132 | #endif 133 | 134 | /** 135 | * @brief Macro defining the maximum digest length of the specified hash function, 136 | * used to determine the length of the output buffer. 137 | * 138 | * This macro should be updated if using a hashing algorithm other than SHA256 139 | * (32 byte digest length). For example, using SHA512 would require this 140 | * value to be at least 64. 141 | * 142 | * Possible values: Any positive 32 bit integer.
143 | * Default value: `32` 144 | */ 145 | #ifndef SIGV4_HASH_MAX_DIGEST_LENGTH 146 | #define SIGV4_HASH_MAX_DIGEST_LENGTH 32U 147 | #endif 148 | 149 | /** 150 | * @brief Macro to statically enable support for canonicalizing the URI, 151 | * headers, and query in this library. 152 | * 153 | * Set this to one to enable the encoding functions used to create the canonical 154 | * request. 155 | * 156 | * Possible values: 0 or 1
157 | * Default value: `1` 158 | */ 159 | #ifndef SIGV4_USE_CANONICAL_SUPPORT 160 | #define SIGV4_USE_CANONICAL_SUPPORT 1 161 | #endif 162 | 163 | /** 164 | * @brief Macro called by the SigV4 library for logging "Error" level 165 | * messages. 166 | * 167 | * To enable error level logging in the SigV4 library, this macro should 168 | * be mapped to the application-specific logging implementation that supports 169 | * error logging. 170 | * 171 | * @note This logging macro is called in the SigV4 library with 172 | * parameters wrapped in double parentheses to be ISO C89/C90 standard 173 | * compliant. For a reference POSIX implementation of the logging macros, refer 174 | * to sigv4_config.h files, and the logging-stack in demos folder of the [AWS 175 | * IoT Embedded C SDK 176 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C). 177 | * 178 | * Default value: Error logging is turned off, and no code is generated 179 | * for calls to the macro in the SigV4 library on compilation. 180 | */ 181 | #ifndef LogError 182 | #define LogError( message ) 183 | #endif 184 | 185 | /** 186 | * @brief Macro called by the the SigV4 library for logging "Warning" 187 | * level messages. 188 | * 189 | * To enable warning level logging in the SigV4 library, this macro 190 | * should be mapped to the application-specific logging implementation that 191 | * supports warning logging. 192 | * 193 | * @note This logging macro is called in the SigV4 library with 194 | * parameters wrapped in double parentheses to be ISO C89/C90 standard 195 | * compliant. For a reference POSIX implementation of the logging macros, refer 196 | * to sigv4_config.h files, and the logging-stack in demos folder of the [AWS 197 | * IoT Embedded C SDK 198 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C). 199 | * 200 | * Default value: Warning logs are turned off, and no code is generated 201 | * for calls to the macro in the SigV4 library on compilation. 202 | */ 203 | #ifndef LogWarn 204 | #define LogWarn( message ) 205 | #endif 206 | 207 | /** 208 | * @brief Macro called by the the SigV4 library for logging "Info" level 209 | * messages. 210 | * 211 | * To enable info level logging in the SigV4 library, this macro should 212 | * be mapped to the application-specific logging implementation that supports 213 | * info logging. 214 | * 215 | * @note This logging macro is called in the SigV4 library with 216 | * parameters wrapped in double parentheses to be ISO C89/C90 standard 217 | * compliant. For a reference POSIX implementation of the logging macros, refer 218 | * to sigv4_config.h files, and the logging-stack in demos folder of the [AWS 219 | * IoT Embedded C SDK 220 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C). 221 | * 222 | * Default value: Info logging is turned off, and no code is generated 223 | * for calls to the macro in the SigV4 library on compilation. 224 | */ 225 | #ifndef LogInfo 226 | #define LogInfo( message ) 227 | #endif 228 | 229 | /** 230 | * @brief Macro called by the the SigV4 library for logging "Debug" 231 | * level messages. 232 | * 233 | * To enable debug level logging from SigV4 library, this macro should 234 | * be mapped to the application-specific logging implementation that supports 235 | * debug logging. 236 | * 237 | * @note This logging macro is called in the SigV4 library with 238 | * parameters wrapped in double parentheses to be ISO C89/C90 standard 239 | * compliant. For a reference POSIX implementation of the logging macros, refer 240 | * to sigv4_config.h files, and the logging-stack in demos folder of the [AWS 241 | * IoT Embedded C SDK 242 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C). 243 | * 244 | * Default value: Debug logging is turned off, and no code is generated 245 | * for calls to the macro in the SigV4 library on compilation. 246 | */ 247 | #ifndef LogDebug 248 | #define LogDebug( message ) 249 | #endif 250 | 251 | /* *INDENT-OFF* */ 252 | #ifdef __cplusplus 253 | } 254 | #endif 255 | /* *INDENT-ON* */ 256 | 257 | #endif /* ifndef SIGV4_CONFIG_DEFAULTS_H_ */ 258 | -------------------------------------------------------------------------------- /source/include/sigv4_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_internal.h 27 | * @brief Internal definitions for the SigV4 Library. 28 | */ 29 | 30 | #ifndef SIGV4_INTERNAL_H_ 31 | #define SIGV4_INTERNAL_H_ 32 | 33 | /* *INDENT-OFF* */ 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | /* *INDENT-ON* */ 38 | 39 | /* SIGV4_DO_NOT_USE_CUSTOM_CONFIG allows building of the SigV4 library without a 40 | * config file. If a config file is provided, the SIGV4_DO_NOT_USE_CUSTOM_CONFIG 41 | * macro must not be defined. 42 | */ 43 | #ifndef SIGV4_DO_NOT_USE_CUSTOM_CONFIG 44 | #include "sigv4_config.h" 45 | #endif 46 | 47 | /* Include config defaults header to get default values of configurations not 48 | * defined in sigv4_config.h file. */ 49 | #include "sigv4_config_defaults.h" 50 | 51 | /* Constants for date verification. */ 52 | #define YEAR_MIN 1900L /**< Earliest year accepted. */ 53 | #define MONTH_ASCII_LEN 3U /**< Length of month abbreviations. */ 54 | 55 | /** 56 | * @brief Month name abbreviations for RFC 5322 date parsing. 57 | */ 58 | #define MONTH_NAMES { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } 59 | 60 | /** 61 | * @brief Number of days in each respective month. 62 | */ 63 | #define MONTH_DAYS { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 64 | 65 | #define FORMAT_RFC_3339 "%4Y-%2M-%2DT%2h:%2m:%2sZ" /**< Format string to parse RFC 3339 date. */ 66 | #define FORMAT_RFC_3339_LEN sizeof( FORMAT_RFC_3339 ) - 1U /**< Length of the RFC 3339 format string. */ 67 | 68 | #define FORMAT_RFC_5322 "%3*, %2D %3M %4Y %2h:%2m:%2s GMT" /**< Format string to parse RFC 5322 date. */ 69 | #define FORMAT_RFC_5322_LEN sizeof( FORMAT_RFC_5322 ) - 1U /**< Length of the RFC 3339 format string. */ 70 | 71 | #define ISO_YEAR_LEN 4U /**< Length of year value in ISO 8601 date. */ 72 | #define ISO_NON_YEAR_LEN 2U /**< Length of non-year values in ISO 8601 date. */ 73 | 74 | #define ISO_DATE_SCOPE_LEN 8U /**< Length of date substring used in credential scope. */ 75 | 76 | /* SigV4 related string literals and lengths. */ 77 | 78 | /** 79 | * @brief The separator between each component of the credential scope. 80 | */ 81 | #define CREDENTIAL_SCOPE_SEPARATOR '/' 82 | #define CREDENTIAL_SCOPE_SEPARATOR_LEN 1U /**< The length of #CREDENTIAL_SCOPE_SEPARATOR. */ 83 | 84 | /** 85 | * @brief The last component that terminates the credential scope. 86 | */ 87 | #define CREDENTIAL_SCOPE_TERMINATOR "aws4_request" 88 | #define CREDENTIAL_SCOPE_TERMINATOR_LEN ( sizeof( CREDENTIAL_SCOPE_TERMINATOR ) - 1U ) /**< The length of #CREDENTIAL_SCOPE_TERMINATOR. */ 89 | 90 | /** 91 | * @brief Default value when HttpParameters_t.pPath == NULL. 92 | */ 93 | #define HTTP_EMPTY_PATH "/" 94 | #define HTTP_EMPTY_PATH_LEN ( sizeof( HTTP_EMPTY_PATH ) - 1U ) /**< The length of #HTTP_EMPTY_PATH. */ 95 | 96 | #define URI_ENCODED_SPECIAL_CHAR_SIZE 3U /**< The size of an encoded URI special character. */ 97 | #define URI_DOUBLE_ENCODED_EQUALS_CHAR_SIZE 5U /**< The size of the double-encoded "=" character. */ 98 | 99 | #define LINEFEED_CHAR '\n' /**< A linefeed character used to build the canonical request. */ 100 | #define LINEFEED_CHAR_LEN 1U /**< The length of #LINEFEED_CHAR. */ 101 | 102 | #define HTTP_REQUEST_LINE_ENDING "\r\n" /**< The string used in non-canonicalized HTTP headers to separate header entries in HTTP request. */ 103 | #define HTTP_REQUEST_LINE_ENDING_LEN ( sizeof( HTTP_REQUEST_LINE_ENDING ) - 1U ) /**< The length of #HTTP_REQUEST_LINE_ENDING. */ 104 | 105 | #define SPACE_CHAR ' ' /**< A linefeed character used to build the Authorization header value. */ 106 | #define SPACE_CHAR_LEN 1U /**< The length of #SPACE_CHAR. */ 107 | 108 | #define S3_SERVICE_NAME "s3" /**< S3 is the only service where the URI must only be encoded once. */ 109 | #define S3_SERVICE_NAME_LEN ( sizeof( S3_SERVICE_NAME ) - 1U ) /**< The length of #S3_SERVICE_NAME. */ 110 | 111 | #define SIGV4_HMAC_SIGNING_KEY_PREFIX "AWS4" /**< HMAC signing key prefix. */ 112 | #define SIGV4_HMAC_SIGNING_KEY_PREFIX_LEN ( sizeof( SIGV4_HMAC_SIGNING_KEY_PREFIX ) - 1U ) /**< The length of #SIGV4_HMAC_SIGNING_KEY_PREFIX. */ 113 | 114 | #define AUTH_CREDENTIAL_PREFIX "Credential=" /**< The prefix that goes before the credential value in the Authorization header value. */ 115 | #define AUTH_CREDENTIAL_PREFIX_LEN ( sizeof( AUTH_CREDENTIAL_PREFIX ) - 1U ) /**< The length of #AUTH_CREDENTIAL_PREFIX. */ 116 | #define AUTH_SEPARATOR ", " /**< The separator between each component in the Authorization header value. */ 117 | #define AUTH_SEPARATOR_LEN ( sizeof( AUTH_SEPARATOR ) - 1U ) /**< The length of #AUTH_SEPARATOR. */ 118 | #define AUTH_SIGNED_HEADERS_PREFIX "SignedHeaders=" /**< The prefix that goes before the signed headers in the Authorization header value. */ 119 | #define AUTH_SIGNED_HEADERS_PREFIX_LEN ( sizeof( AUTH_SIGNED_HEADERS_PREFIX ) - 1U ) /**< The length of #AUTH_SIGNED_HEADERS_PREFIX. */ 120 | #define AUTH_SIGNATURE_PREFIX "Signature=" /**< The prefix that goes before the signature in the Authorization header value. */ 121 | #define AUTH_SIGNATURE_PREFIX_LEN ( sizeof( AUTH_SIGNATURE_PREFIX ) - 1U ) /**< The length of #AUTH_SIGNATURE_PREFIX. */ 122 | 123 | #define HMAC_INNER_PAD_BYTE ( 0x36U ) /**< The "ipad" byte used for generating the inner key in the HMAC calculation process. */ 124 | #define HMAC_OUTER_PAD_BYTE ( 0x5CU ) /**< The "opad" byte used for generating the outer key in the HMAC calculation process. */ 125 | #define HMAX_IPAD_XOR_OPAD_BYTE ( 0x6AU ) /**< The XOR of the "ipad" and "opad" bytes to extract outer key from inner key. */ 126 | 127 | /** 128 | * @brief A helper macro to print insufficient memory errors. 129 | */ 130 | #define LOG_INSUFFICIENT_MEMORY_ERROR( purposeOfWrite, bytesExceeded ) \ 131 | { \ 132 | LogError( ( "Unable to " purposeOfWrite ": Insufficient memory configured in SIGV4_PROCESSING_BUFFER_LENGTH macro. BytesExceeded=%lu", \ 133 | ( unsigned long ) ( bytesExceeded ) ) ); \ 134 | } 135 | 136 | /** 137 | * @brief A helper macro to test if a flag is set. 138 | */ 139 | #define FLAG_IS_SET( bits, flag ) ( ( ( bits ) & ( flag ) ) == ( flag ) ) 140 | 141 | /** 142 | * @brief A helper macro to determine if a character is whitespace. 143 | * @note The ctype function isspace() returns true for the following characters: 144 | * ` `, `\t`, `\n`, `\v`, `\f`, `\r`. However, according to RFC5234: 145 | * https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1 146 | * the only whitespace characters in an HTTP header are spaces and 147 | * horizontal tabs. 148 | */ 149 | #define isWhitespace( c ) ( ( ( c ) == ' ' ) || ( ( c ) == '\t' ) ) 150 | 151 | /** 152 | * @brief An aggregator representing the individually parsed elements of the 153 | * user-provided date parameter. This is used to verify the complete date 154 | * representation, and construct the final ISO 8601 string. 155 | */ 156 | typedef struct SigV4DateTime 157 | { 158 | int32_t year; /**< Year (1900 or later) */ 159 | int32_t mon; /**< Month (1 to 12) */ 160 | int32_t mday; /**< Day of Month (1 to 28/29/30/31) */ 161 | int32_t hour; /**< Hour (0 to 23) */ 162 | int32_t min; /**< Minutes (0 to 59) */ 163 | int32_t sec; /**< Seconds (0 to 60) */ 164 | } SigV4DateTime_t; 165 | 166 | /** 167 | * @brief A library structure holding the string and length values of parameters to 168 | * be sorted and standardized. This allows for a layer of abstraction during the 169 | * canonicalization step of the V4 signing process. 170 | */ 171 | typedef struct SigV4String 172 | { 173 | char * pData; /**< SigV4 string data */ 174 | size_t dataLen; /**< Length of pData */ 175 | } SigV4String_t; 176 | 177 | /** 178 | * @brief A library structure holding the string and length values of parameters to 179 | * be sorted and standardized. This allows for a layer of abstraction during the 180 | * canonicalization step of the V4 signing process. 181 | */ 182 | typedef struct SigV4ConstString 183 | { 184 | const char * pData; /**< SigV4 string data */ 185 | size_t dataLen; /**< Length of pData */ 186 | } SigV4ConstString_t; 187 | 188 | /** 189 | * @brief A key-value pair data structure that allows for sorting of SigV4 190 | * string values using internal comparison functions, and provides additional 191 | * stability to quickSort(), to comply with Misra rule 21.9. 192 | */ 193 | typedef struct SigV4KeyValuePair 194 | { 195 | SigV4ConstString_t key; /**< SigV4 string identifier */ 196 | SigV4ConstString_t value; /**< SigV4 data */ 197 | } SigV4KeyValuePair_t; 198 | 199 | /** 200 | * @brief An aggregator to maintain the internal state of canonicalization 201 | * during intermediate calculations. 202 | */ 203 | typedef struct CanonicalContext 204 | { 205 | SigV4KeyValuePair_t pQueryLoc[ SIGV4_MAX_QUERY_PAIR_COUNT ]; /**< Query pointers used during sorting. */ 206 | SigV4KeyValuePair_t pHeadersLoc[ SIGV4_MAX_HTTP_HEADER_COUNT ]; /**< Header pointers used during sorting. */ 207 | 208 | uint8_t pBufProcessing[ SIGV4_PROCESSING_BUFFER_LENGTH ]; /**< Internal calculation buffer used during canonicalization. */ 209 | size_t uxCursorIndex; /**< pBufProcessing cursor. */ 210 | size_t bufRemaining; /**< pBufProcessing value used during internal calculation. */ 211 | const char * pHashPayloadLoc; /**< Pointer used to store the location of hashed HTTP request payload. */ 212 | size_t hashPayloadLen; /**< Length of hashed HTTP request payload. */ 213 | } CanonicalContext_t; 214 | 215 | /** 216 | * @brief An aggregator to maintain the internal state of HMAC 217 | * calculations. 218 | */ 219 | typedef struct HmacContext 220 | { 221 | /** 222 | * @brief The cryptography interface. 223 | */ 224 | const SigV4CryptoInterface_t * pCryptoInterface; 225 | 226 | /** 227 | * @brief All accumulated key data. 228 | */ 229 | uint8_t key[ SIGV4_HASH_MAX_BLOCK_LENGTH ]; 230 | 231 | /** 232 | * @brief The length of the accumulated key data. 233 | */ 234 | size_t keyLen; 235 | } HmacContext_t; 236 | 237 | /* *INDENT-OFF* */ 238 | #ifdef __cplusplus 239 | } 240 | #endif 241 | /* *INDENT-ON* */ 242 | 243 | #endif /* ifndef SIGV4_INTERNAL_H_ */ 244 | -------------------------------------------------------------------------------- /source/include/sigv4_quicksort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_quicksort.h 27 | * @brief Declaration of Quicksort function for the SigV4 Library. 28 | */ 29 | 30 | #ifndef SIGV4_QUICKSORT_H_ 31 | #define SIGV4_QUICKSORT_H_ 32 | 33 | /* Standard includes. */ 34 | #include 35 | #include 36 | 37 | /* *INDENT-OFF* */ 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | /* *INDENT-ON* */ 42 | 43 | /* SIGV4_DO_NOT_USE_CUSTOM_CONFIG allows building of the SigV4 library without a 44 | * config file. If a config file is provided, the SIGV4_DO_NOT_USE_CUSTOM_CONFIG 45 | * macro must not be defined. 46 | */ 47 | #ifndef SIGV4_DO_NOT_USE_CUSTOM_CONFIG 48 | #include "sigv4_config.h" 49 | #endif 50 | 51 | /* Include config defaults header to get default values of configurations not 52 | * defined in sigv4_config.h file. */ 53 | #include "sigv4_config_defaults.h" 54 | 55 | /** 56 | * @brief The comparison function used for sorting. 57 | * @param[in] pFirstVal The first value to compare 58 | * @param[in] pSecondVal The second value to compare 59 | * 60 | * @return A value less than 0 if @p pFirstVal is less than 61 | * @p pSecondVal. Otherwise, greater than 0. 62 | */ 63 | typedef int32_t ( * ComparisonFunc_t )( const void * pFirstVal, 64 | const void * pSecondVal ); 65 | 66 | /** 67 | * @brief Perform quicksort on an array. 68 | * 69 | * @param[in] pArray The array to be sorted. 70 | * @param[in] numItems The number of items in an array. 71 | * @param[in] itemSize The amount of memory per entry in the array. 72 | * @param[out] comparator The comparison function to determine if one item is less than another. 73 | */ 74 | void quickSort( void * pArray, 75 | size_t numItems, 76 | size_t itemSize, 77 | ComparisonFunc_t comparator ); 78 | 79 | /* *INDENT-OFF* */ 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | /* *INDENT-ON* */ 84 | 85 | #endif /* ifndef SIGV4_QUICKSORT_H_ */ 86 | -------------------------------------------------------------------------------- /source/sigv4_quicksort.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_quicksort.c 27 | * @brief Implements an Iterative Quicksort Algorithm for the SigV4 Library. 28 | */ 29 | 30 | #include "sigv4_quicksort.h" 31 | 32 | #include 33 | #include 34 | 35 | /** 36 | * @brief Push a value to the stack. 37 | */ 38 | #define PUSH_STACK( valueToPush, stack, index ) \ 39 | { \ 40 | ( stack )[ ( index ) ] = ( valueToPush ); \ 41 | ++( index ); \ 42 | } 43 | 44 | /** 45 | * @brief Pop a value from the stack. 46 | */ 47 | #define POP_STACK( valueToPop, stack, index ) \ 48 | { \ 49 | --( index ); \ 50 | ( valueToPop ) = ( stack )[ ( index ) ]; \ 51 | } 52 | 53 | /*-----------------------------------------------------------*/ 54 | 55 | /** 56 | * @brief A helper function to swap the value of two pointers 57 | * given their sizes. 58 | * 59 | * @param[in] pFirstItem The item to swap with @p pSecondItem. 60 | * @param[in] pSecondItem The item to swap with @p pFirstItem. 61 | * @param[in] itemSize The amount of memory per entry in the array. 62 | */ 63 | static void swap( void * pFirstItem, 64 | void * pSecondItem, 65 | size_t itemSize ); 66 | 67 | /** 68 | * @brief A helper function to perform quicksort on a subarray. 69 | * 70 | * @param[in] pArray The array to be sorted. 71 | * @param[in] low The low index of the array. 72 | * @param[in] high The high index of the array. 73 | * @param[in] itemSize The amount of memory per entry in the array. 74 | * @param[out] comparator The comparison function to determine if one item is less than another. 75 | */ 76 | static void quickSortHelper( void * pArray, 77 | size_t low, 78 | size_t high, 79 | size_t itemSize, 80 | ComparisonFunc_t comparator ); 81 | 82 | /** 83 | * @brief A helper function to partition a subarray using the last element 84 | * of the array as the pivot. All items smaller than the pivot end up 85 | * at its left while all items greater than end up at its right. 86 | * 87 | * @param[in] pArray The array to be sorted. 88 | * @param[in] low The low index of the array. 89 | * @param[in] high The high index of the array. 90 | * @param[in] itemSize The amount of memory per entry in the array. 91 | * @param[out] comparator The comparison function to determine if one item is less than another. 92 | * 93 | * @return The index of the pivot 94 | */ 95 | static size_t partition( void * pArray, 96 | size_t low, 97 | size_t high, 98 | size_t itemSize, 99 | ComparisonFunc_t comparator ); 100 | 101 | /*-----------------------------------------------------------*/ 102 | 103 | static void swap( void * pFirstItem, 104 | void * pSecondItem, 105 | size_t itemSize ) 106 | { 107 | uint8_t * pFirstByte = pFirstItem; 108 | uint8_t * pSecondByte = pSecondItem; 109 | size_t dataSize = itemSize; 110 | 111 | assert( pFirstItem != NULL ); 112 | assert( pSecondItem != NULL ); 113 | 114 | /* Swap one byte at a time. */ 115 | while( dataSize-- > 0U ) 116 | { 117 | uint8_t tmp = *pFirstByte; 118 | *pFirstByte = *pSecondByte; 119 | ++pFirstByte; 120 | *pSecondByte = tmp; 121 | ++pSecondByte; 122 | } 123 | } 124 | 125 | static void quickSortHelper( void * pArray, 126 | size_t low, 127 | size_t high, 128 | size_t itemSize, 129 | ComparisonFunc_t comparator ) 130 | { 131 | size_t stack[ SIGV4_WORST_CASE_SORT_STACK_SIZE ]; 132 | 133 | /* Low and high are first two items on the stack. Note 134 | * that we use an intermediary variable for MISRA compliance. */ 135 | size_t top = 0U, lo = low, hi = high; 136 | 137 | PUSH_STACK( lo, stack, top ); 138 | PUSH_STACK( hi, stack, top ); 139 | 140 | while( top > 0U ) 141 | { 142 | size_t partitionIndex; 143 | size_t len1, len2; 144 | POP_STACK( hi, stack, top ); 145 | POP_STACK( lo, stack, top ); 146 | 147 | partitionIndex = partition( pArray, lo, hi, itemSize, comparator ); 148 | 149 | /* Calculate length of the left partition containing items smaller 150 | * than the pivot element. 151 | * The length is zero if either: 152 | * 1. The pivoted item is the smallest in the the array before partitioning. 153 | * OR 154 | * 2. The left partition is only of single length which can be treated as 155 | * sorted, and thus, of zero length for avoided adding to the stack. */ 156 | len1 = ( ( partitionIndex != 0U ) && ( ( partitionIndex - 1U ) > lo ) ) ? ( partitionIndex - lo ) : 0U; 157 | 158 | /* Calculate length of the right partition containing items greater than 159 | * or equal to the pivot item. 160 | * The calculated length is zero if either: 161 | * 1. The pivoted item is the greatest in the the array before partitioning. 162 | * OR 163 | * 2. The right partition contains only a single length which can be treated as 164 | * sorted, and thereby, of zero length to avoid adding to the stack. */ 165 | len2 = ( ( partitionIndex + 1U ) < hi ) ? ( hi - partitionIndex ) : 0U; 166 | 167 | /* Push the information of the left and right partitions to the stack. 168 | * Note: For stack space optimization, the larger of the partitions is pushed 169 | * first and the smaller is pushed later so that the smaller part of the tree 170 | * is completed first without increasing stack space usage before coming back 171 | * to the larger partition. */ 172 | if( len1 > len2 ) 173 | { 174 | PUSH_STACK( lo, stack, top ); 175 | PUSH_STACK( partitionIndex - 1U, stack, top ); 176 | 177 | if( len2 > 0U ) 178 | { 179 | PUSH_STACK( partitionIndex + 1U, stack, top ); 180 | PUSH_STACK( hi, stack, top ); 181 | } 182 | } 183 | else 184 | { 185 | if( len2 > 0U ) 186 | { 187 | PUSH_STACK( partitionIndex + 1U, stack, top ); 188 | PUSH_STACK( hi, stack, top ); 189 | } 190 | 191 | if( len1 > 0U ) 192 | { 193 | PUSH_STACK( lo, stack, top ); 194 | PUSH_STACK( partitionIndex - 1U, stack, top ); 195 | } 196 | } 197 | } 198 | } 199 | 200 | static size_t partition( void * pArray, 201 | size_t low, 202 | size_t high, 203 | size_t itemSize, 204 | ComparisonFunc_t comparator ) 205 | { 206 | uint8_t * pivot; 207 | uint8_t * pArrayLocal = ( uint8_t * ) pArray; 208 | size_t i = low - 1U, j = low; 209 | 210 | assert( pArray != NULL ); 211 | assert( comparator != NULL ); 212 | 213 | /* Choose pivot as the highest indexed item in the current partition. */ 214 | pivot = &( pArrayLocal[ high * itemSize ] ); 215 | 216 | /* Iterate over all elements of the current array to partition it 217 | * in comparison to the chosen pivot with smaller items on the left 218 | * and larger or equal to items on the right. */ 219 | for( ; j < high; j++ ) 220 | { 221 | /* Use comparator function to check current element is smaller than the pivot */ 222 | if( comparator( &( pArrayLocal[ j * itemSize ] ), pivot ) < 0 ) 223 | { 224 | ++i; 225 | swap( &( pArrayLocal[ i * itemSize ] ), &( pArrayLocal[ j * itemSize ] ), itemSize ); 226 | } 227 | } 228 | 229 | /* Place the pivot between the smaller and larger item chunks of 230 | * the array. This represents the 2 partitions of the array. */ 231 | swap( &( pArrayLocal[ ( i + 1U ) * itemSize ] ), pivot, itemSize ); 232 | 233 | /* Return the pivot item's index. */ 234 | return i + 1U; 235 | } 236 | 237 | void quickSort( void * pArray, 238 | size_t numItems, 239 | size_t itemSize, 240 | ComparisonFunc_t comparator ) 241 | { 242 | assert( pArray != NULL ); 243 | assert( numItems > 0U ); 244 | assert( itemSize > 0U ); 245 | assert( comparator != NULL ); 246 | 247 | quickSortHelper( pArray, 0U, numItems - 1U, itemSize, comparator ); 248 | } 249 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project information. 2 | cmake_minimum_required( VERSION 3.13.0 ) 3 | project( "SigV4 tests" 4 | VERSION 1.3.0 5 | LANGUAGES C ) 6 | 7 | # Allow the project to be organized into folders. 8 | set_property( GLOBAL PROPERTY USE_FOLDERS ON ) 9 | 10 | set( CMAKE_C_STANDARD 99 ) 11 | set( CMAKE_C_STANDARD_REQUIRED ON ) 12 | 13 | # Do not allow in-source build. 14 | if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} ) 15 | message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." ) 16 | endif() 17 | 18 | # Set global path variables. 19 | get_filename_component( __MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE ) 20 | set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "SigV4 repository root." ) 21 | 22 | # Configure options to always show in CMake GUI. 23 | # If no configuration is defined, turn everything on. 24 | if( NOT DEFINED COV_ANALYSIS AND NOT DEFINED UNITTEST ) 25 | set( COV_ANALYSIS ON ) 26 | set( UNITTEST OFF ) # Default set to OFF for backward compatibility 27 | endif() 28 | 29 | # Set output directories. 30 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) 31 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 32 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 33 | 34 | # ====================== Coverity Analysis Configuration ====================== 35 | # Include filepaths for source and include. 36 | include( ${MODULE_ROOT_DIR}/sigv4FilePaths.cmake ) 37 | 38 | if( COV_ANALYSIS ) 39 | # Target for Coverity analysis that builds the library. 40 | add_library( coverity_analysis 41 | ${SIGV4_SOURCES} ) 42 | 43 | # Verify ISO C90 compliance of libray. 44 | target_compile_options( coverity_analysis PUBLIC -std=c90 ) 45 | 46 | # SigV4 public include path and test config file 47 | target_include_directories( coverity_analysis 48 | PUBLIC 49 | ${SIGV4_INCLUDE_PUBLIC_DIRS} 50 | "${CMAKE_CURRENT_LIST_DIR}/include" ) 51 | 52 | # Build without debug enabled when performing static analysis 53 | target_compile_options(coverity_analysis PUBLIC -DNDEBUG -DDISABLE_LOGGING) 54 | endif() 55 | 56 | # ============================ Test Configuration ============================ 57 | if( UNITTEST ) 58 | # Define a CMock resource path. 59 | set( CMOCK_DIR ${MODULE_ROOT_DIR}/test/unit-test/CMock CACHE INTERNAL "CMock library source directory." ) 60 | 61 | # Include CMock build configuration. 62 | include( unit-test/cmock_build.cmake ) 63 | 64 | # Check if the CMock source directory exists, and if not present, clone the submodule 65 | # if BUILD_CLONE_SUBMODULES configuration is enabled. 66 | if( NOT EXISTS ${CMOCK_DIR}/src ) 67 | # Attempt to clone CMock. 68 | clone_cmock() 69 | endif() 70 | 71 | # Add unit test and coverage configuration. 72 | 73 | # Use CTest utility for managing test runs. This has to be added BEFORE 74 | # defining test targets with add_test() 75 | enable_testing() 76 | 77 | # Add build targets for CMock and Unit, required for unit testing. 78 | add_cmock_targets() 79 | 80 | # Add function to enable CMock based tests and coverage. 81 | include( ${MODULE_ROOT_DIR}/tools/cmock/create_test.cmake ) 82 | 83 | # Include build configuration for unit tests. 84 | add_subdirectory( unit-test ) 85 | 86 | # ==================== Coverage Analysis configuration ======================== 87 | 88 | # Add a target for running coverage on tests. 89 | add_custom_target( coverage 90 | COMMAND ${CMAKE_COMMAND} -DCMOCK_DIR=${CMOCK_DIR} 91 | -P ${MODULE_ROOT_DIR}/tools/cmock/coverage.cmake 92 | DEPENDS cmock unity sigv4_utest 93 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 94 | ) 95 | endif() 96 | -------------------------------------------------------------------------------- /test/cbmc/.gitignore: -------------------------------------------------------------------------------- 1 | # Emitted when running CBMC proofs 2 | proofs/**/logs 3 | proofs/**/gotos 4 | proofs/**/report 5 | proofs/**/html 6 | proofs/output 7 | 8 | # Emitted by CBMC Viewer 9 | TAGS-* 10 | 11 | # Emitted by Arpa 12 | arpa_cmake/ 13 | arpa-validation-logs/ 14 | Makefile.arpa 15 | 16 | # Emitted by litani 17 | .ninja_deps 18 | .ninja_log 19 | .litani_cache_dir 20 | 21 | # These files should be overwritten whenever prepare.py runs 22 | cbmc-batch.yaml 23 | 24 | __pycache__/ 25 | -------------------------------------------------------------------------------- /test/cbmc/include/README.md: -------------------------------------------------------------------------------- 1 | CBMC proof include files 2 | ======================== 3 | 4 | This directory contains include files written for CBMC proof. It is 5 | common to write some code to model aspects of the system under test, 6 | and the header files for this code go here. 7 | -------------------------------------------------------------------------------- /test/cbmc/include/hash_stubs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file hash_stubs.h 27 | * @brief Declarations for stubs used in sigv4.c. 28 | * Please see sigv4.c for documentation. 29 | */ 30 | 31 | #ifndef HASH_STUBS_H_ 32 | #define HASH_STUBS_H_ 33 | 34 | /* Standard includes. */ 35 | #include 36 | #include 37 | #include 38 | 39 | int32_t HashInitStub( void * pHashContext ); 40 | 41 | int32_t HashUpdateStub( void * pHashContext, 42 | const char * pInput, 43 | size_t inputLen ); 44 | 45 | int32_t HashFinalStub( void * pHashContext, 46 | const char * pInput, 47 | size_t inputLen ); 48 | 49 | #endif /* ifndef HASH_STUBS_H_ */ 50 | -------------------------------------------------------------------------------- /test/cbmc/include/sigv4_annex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #ifndef SIGV4_ANNEX_H_ 26 | #define SIGV4_ANNEX_H_ 27 | 28 | #include "sigv4.h" 29 | #include "sigv4_internal.h" 30 | 31 | /* 32 | * These are declarations for the (normally) static functions from sigv4.c. 33 | * Please see sigv4.c for documentation. 34 | */ 35 | 36 | SigV4Status_t copyHeaderStringToCanonicalBuffer( const char * pData, 37 | size_t dataLen, 38 | uint32_t flags, 39 | char separator, 40 | CanonicalContext_t * canonicalRequest ); 41 | 42 | #endif /* ifndef SIGV4_ANNEX_H_ */ 43 | -------------------------------------------------------------------------------- /test/cbmc/include/sigv4_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_config.h 27 | * @brief The default values for configuration macros used by the SigV4 Library. 28 | * 29 | * @note This file should NOT be modified. If custom values are needed for any 30 | * configuration macros, a sigv4_config.h file should be provided to the SigV4 31 | * Library to override the default values defined in this file. To use 32 | * the custom config file, the preprocessor macro SIGV4_DO_NOT_USE_CUSTOM_CONFIG 33 | * must NOT be set. 34 | */ 35 | 36 | #ifndef SIGV4_CONFIG_H_ 37 | #define SIGV4_CONFIG_H_ 38 | 39 | /** 40 | * @brief Macro indicating the largest block size of any hashing 41 | * algorithm used for SigV4 authentication i.e. the maximum of all 42 | * values specified for the hashBlockLen in #SigV4CryptoInterface_t. 43 | * For example, using SHA-512 would require this value to be at least 128. 44 | * 45 | * Possible values: Any positive 32 bit integer.
46 | * Default value: `64` 47 | */ 48 | #define SIGV4_HASH_MAX_BLOCK_LENGTH ( MAX_HASH_BLOCK_LEN - 1U ) 49 | 50 | /** 51 | * @brief Macro defining the maximum digest length of the specified hash function, 52 | * used to determine the length of the output buffer. 53 | * 54 | * This macro should be updated if using a hashing algorithm other than SHA256 55 | * (32 byte digest length). For example, using SHA512 would require this 56 | * value to be at least 64. 57 | * 58 | * Possible values: Any positive 32 bit integer.
59 | * Default value: `32` 60 | */ 61 | #define SIGV4_HASH_MAX_DIGEST_LENGTH ( MAX_HASH_DIGEST_LEN - 1U ) 62 | 63 | /** 64 | * @brief Macro defining the size of the internal buffer used for incremental 65 | * canonicalization and hashing. 66 | * 67 | * A buffer of this size in bytes is declared on the stack. It should be be 68 | * large enough for the digest output of the specified hash function. 69 | * 70 | * Possible values: Any positive 32 bit integer.
71 | * Default value: `1024` 72 | */ 73 | #ifndef SIGV4_PROCESSING_BUFFER_LENGTH 74 | #define SIGV4_PROCESSING_BUFFER_LENGTH 60U 75 | #endif 76 | 77 | /** 78 | * @brief Macro defining the maximum number of headers in the request, used to 79 | * assist the library in sorting header fields during canonicalization. 80 | * 81 | * This macro should be updated if the number of request headers the application 82 | * wishes to sign is higher or lower than the default value (100). 83 | * 84 | * Possible values: Any positive 32 bit integer.
85 | * Default value: `100` 86 | */ 87 | #ifndef SIGV4_MAX_HTTP_HEADER_COUNT 88 | #define SIGV4_MAX_HTTP_HEADER_COUNT 5U 89 | #endif 90 | 91 | /** 92 | * @brief Macro defining the maximum number of query key/value pairs, used to 93 | * assist the library in sorting query keys during canonicalization. 94 | * 95 | * This macro should be updated if the number of query key/value pairs the 96 | * application wishes to sign is higher or lower than the default value (100). 97 | * 98 | * Possible values: Any positive 32 bit integer.
99 | * Default value: `100` 100 | */ 101 | #ifndef SIGV4_MAX_QUERY_PAIR_COUNT 102 | #define SIGV4_MAX_QUERY_PAIR_COUNT 5U 103 | #endif 104 | 105 | #endif /* ifndef SIGV4_CONFIG_H_ */ 106 | -------------------------------------------------------------------------------- /test/cbmc/include/sigv4_stubs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_stubs.h 27 | * @brief Declarations for the (normally) static functions from sigv4.c. 28 | * Please see sigv4.c for documentation. 29 | */ 30 | 31 | #ifndef SIGV4_STUBS_H_ 32 | #define SIGV4_STUBS_H_ 33 | 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | void addToDate( const char formatChar, 40 | int32_t result, 41 | SigV4DateTime_t * pDateElements ); 42 | 43 | SigV4Status_t scanValue( const char * pDate, 44 | const char formatChar, 45 | size_t readLoc, 46 | size_t lenToRead, 47 | SigV4DateTime_t * pDateElements ); 48 | 49 | SigV4Status_t writeLineToCanonicalRequest( const char * pLine, 50 | size_t lineLen, 51 | CanonicalContext_t * pCanonicalContext ); 52 | 53 | SigV4Status_t SigV4_EncodeURI( const char * pUri, 54 | size_t uriLen, 55 | char * pCanonicalURI, 56 | size_t * canonicalURILen, 57 | bool encodeSlash, 58 | bool doubleEncodeEquals ); 59 | 60 | SigV4Status_t generateCanonicalQuery( const char * pQuery, 61 | size_t queryLen, 62 | const bool doubleEncodeEqualsInParmsValues, 63 | CanonicalContext_t * pCanonicalContext ); 64 | 65 | SigV4Status_t generateCanonicalAndSignedHeaders( const char * pHeaders, 66 | size_t headersLen, 67 | uint32_t flags, 68 | CanonicalContext_t * canonicalRequest, 69 | char ** pSignedHeaders, 70 | size_t * pSignedHeadersLen ); 71 | 72 | SigV4Status_t copyHeaderStringToCanonicalBuffer( const char * pData, 73 | size_t dataLen, 74 | uint32_t flags, 75 | char separator, 76 | CanonicalContext_t * canonicalRequest ); 77 | 78 | #endif /* ifndef SIGV4_STUBS_H_ */ 79 | -------------------------------------------------------------------------------- /test/cbmc/proofs/Makefile-json.common: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | HARNESS_ENTRY=harness 5 | 6 | DEFINES += -DCBMC_MAX_BUFSIZE=$(CBMC_MAX_BUFSIZE) 7 | ifdef CBMC_MAX_QUERYKEYLENGTH 8 | DEFINES += -DCBMC_MAX_QUERYKEYLENGTH=$(CBMC_MAX_QUERYKEYLENGTH) 9 | endif 10 | 11 | INCLUDES += -I$(CBMC_ROOT)/include 12 | 13 | PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c 14 | 15 | PROJECT_SOURCES += $(PROOFDIR)/sigv4.c 16 | PROJECT_SOURCES += $(SRCDIR)/source/sigv4_quicksort.c 17 | 18 | CHECKFLAGS += --pointer-primitive-check 19 | 20 | include ../Makefile.common 21 | 22 | cleanclean: veryclean 23 | -$(RM) $(PROOFDIR)/sigv4.c 24 | -------------------------------------------------------------------------------- /test/cbmc/proofs/Makefile-project-defines: -------------------------------------------------------------------------------- 1 | # -*- mode: makefile -*- 2 | # The first line sets the emacs major mode to Makefile 3 | 4 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | ################################################################ 8 | # Use this file to give project-specific definitions of the command 9 | # line arguments to pass to CBMC tools like goto-cc to build the goto 10 | # binaries and cbmc to do the property and coverage checking. 11 | # 12 | # Use this file to override most default definitions of variables in 13 | # Makefile.common. 14 | ################################################################ 15 | 16 | # Flags to pass to goto-cc for compilation (typically those passed to gcc -c) 17 | # COMPILE_FLAGS = 18 | COMPILE_FLAGS += -fPIC 19 | COMPILE_FLAGS += -std=gnu90 20 | 21 | # Flags to pass to goto-cc for linking (typically those passed to gcc) 22 | # LINK_FLAGS = 23 | 24 | # Preprocessor include paths -I... 25 | # Consider adding 26 | # INCLUDES += -I$(CBMC_ROOT)/include 27 | # You will want to decide what order that comes in relative to the other 28 | # include directories in your project. 29 | # 30 | # INCLUDES = 31 | INCLUDES += -I$(SRCDIR)/test/cbmc/include 32 | INCLUDES += -I$(SRCDIR)/source/include 33 | INCLUDES += -I$(SRCDIR)/test/include 34 | 35 | # Preprocessor definitions -D... 36 | # DEFINES = 37 | DEFINES += 38 | 39 | # Path to arpa executable 40 | # ARPA = 41 | 42 | # Flags to pass to cmake for building the project 43 | # ARPA_CMAKE_FLAGS = 44 | -------------------------------------------------------------------------------- /test/cbmc/proofs/Makefile-project-targets: -------------------------------------------------------------------------------- 1 | # -*- mode: makefile -*- 2 | # The first line sets the emacs major mode to Makefile 3 | 4 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | ################################################################ 8 | # Use this file to give project-specific targets, including targets 9 | # that may depend on targets defined in Makefile.common. 10 | ################################################################ 11 | 12 | # Each proof requires sigv4.c to be patched (using sed) and dumped into the 13 | # proof directory. The exact sed invocation differs for each proof. So each 14 | # proof must set the SIGV4_SED_EXPR variable, which this rule uses as the 15 | # argument to sed. 16 | $(PROOFDIR)/sigv4.c: $(SRCDIR)/source/sigv4.c 17 | $(LITANI) add-job \ 18 | --command \ 19 | "sed -E '$(SIGV4_SED_EXPR)' $^" \ 20 | --inputs $^ \ 21 | --outputs $@ \ 22 | --stdout-file $@ \ 23 | --ci-stage build \ 24 | --pipeline-name "$(PROOF_UID)" \ 25 | --description "$(PROOF_UID): patching sigv4.c" 26 | -------------------------------------------------------------------------------- /test/cbmc/proofs/Makefile-project-testing: -------------------------------------------------------------------------------- 1 | # -*- mode: makefile -*- 2 | # The first line sets the emacs major mode to Makefile 3 | 4 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 | # SPDX-License-Identifier: MIT-0 6 | 7 | ################################################################ 8 | # Use this file to define project-specific targets and definitions for 9 | # unit testing or continuous integration that may depend on targets 10 | # defined in Makefile.common 11 | ################################################################ 12 | -------------------------------------------------------------------------------- /test/cbmc/proofs/Makefile-template-defines: -------------------------------------------------------------------------------- 1 | PROOF_ROOT ?= $(abspath .) 2 | 3 | # Absolute path to the root of the source tree. 4 | # 5 | SRCDIR ?= $(abspath $(PROOF_ROOT)/../../..) 6 | 7 | 8 | # Absolute path to the litani script. 9 | # 10 | LITANI ?= litani 11 | 12 | 13 | # Name of this proof project, displayed in proof reports. For example, 14 | # "s2n" or "Amazon FreeRTOS". For projects with multiple proof roots, 15 | # this may be overridden on the command-line to Make, for example 16 | # 17 | # make PROJECT_NAME="FreeRTOS MQTT" report 18 | # 19 | PROJECT_NAME = "sigv4-for-aws-iot-embedded-sdk" 20 | -------------------------------------------------------------------------------- /test/cbmc/proofs/README.md: -------------------------------------------------------------------------------- 1 | CBMC proofs 2 | =========== 3 | 4 | This directory contains the CBMC proofs. Each proof is in its own 5 | directory. 6 | 7 | This directory includes four Makefiles. 8 | 9 | One Makefile describes the basic workflow for building and running proofs: 10 | 11 | * Makefile.common: 12 | * make: builds the goto binary, does the cbmc property checking 13 | and coverage checking, and builds the final report. 14 | * make goto: builds the goto binary 15 | * make result: does cbmc property checking 16 | * make coverage: does cbmc coverage checking 17 | * make report: builds the final report 18 | 19 | Three included Makefiles describe project-specific settings and can override 20 | definitions in Makefile.common: 21 | 22 | * Makefile-project-defines: definitions like compiler flags 23 | required to build the goto binaries, and definitions to override 24 | definitions in Makefile.common. 25 | * Makefile-project-targets: other make targets needed for the project 26 | * Makefile-project-testing: other definitions and targets needed for 27 | unit testing or continuous integration. 28 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_AwsIotDateToIso8601/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | HARNESS_ENTRY = harness 5 | HARNESS_FILE = SigV4_AwsIotDateToIso8601_harness 6 | 7 | # This should be a unique identifier for this proof, and will appear on the 8 | # Litani dashboard. It can be human-readable and contain spaces if you wish. 9 | PROOF_UID = SigV4_AwsIotDateToIso8601 10 | 11 | DEFINES += -DSIGV4_DO_NOT_USE_CUSTOM_CONFIG=1 12 | INCLUDES += 13 | 14 | MONTH_ASCII_LEN=3 15 | ISO_YEAR_LEN=5 16 | MONTHS_IN_YEAR=12 17 | FORMAT_RFC_5322_LEN=32 18 | 19 | REMOVE_FUNCTION_BODY += 20 | UNWINDSET += parseDate.0:$(FORMAT_RFC_5322_LEN) 21 | UNWINDSET += scanValue.0:$(ISO_YEAR_LEN) 22 | UNWINDSET += intToAscii.0:$(ISO_YEAR_LEN) 23 | 24 | PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c 25 | PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/sigv4_stubs.c 26 | 27 | include ../Makefile-json.common 28 | 29 | # Substitution command to pass to sed for patching sigv4.c. The 30 | # characters " and # must be escaped with backslash. 31 | SIGV4_SED_EXPR = 1s/^/\#include \"sigv4_stubs.h\" /; s/^static //; s/SigV4Status_t scanValue\b/&_/ 32 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_AwsIotDateToIso8601/README.md: -------------------------------------------------------------------------------- 1 | SigV4_AwsIotDateToIso8601 proof 2 | ============== 3 | 4 | This directory contains a memory safety proof for SigV4_AwsIotDateToIso8601. 5 | 6 | To run the proof. 7 | ------------- 8 | 9 | * Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer` 10 | to your path. 11 | * Run `make`. 12 | * Open html/index.html in a web browser. 13 | 14 | To use [`arpa`](https://awslabs.github.io/aws-proof-build-assistant) to simplify writing Makefiles. 15 | ------------- 16 | 17 | * Run `make arpa` to generate a Makefile.arpa that contains relevant build information for the proof. 18 | * Use Makefile.arpa as the starting point for your proof Makefile by: 19 | 1. Modifying Makefile.arpa (if required). 20 | 2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`). 21 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_AwsIotDateToIso8601/SigV4_AwsIotDateToIso8601_harness.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file SigV4_AwsIotDateToIso8601_harness.c 27 | * @brief Implements the proof harness for SigV4_AwsIotDateToIso8601 function. 28 | */ 29 | 30 | #include "stdlib.h" 31 | #include "sigv4.h" 32 | 33 | void harness() 34 | { 35 | char * pInputDate; 36 | size_t dateLen; 37 | char * pDateISO8601; 38 | size_t dateISO8601Len; 39 | SigV4Status_t status; 40 | 41 | __CPROVER_assume( dateLen == SIGV4_EXPECTED_LEN_RFC_3339 || dateLen == SIGV4_EXPECTED_LEN_RFC_5322 || dateLen == 0 ); 42 | 43 | pInputDate = malloc( dateLen ); 44 | 45 | __CPROVER_assume( dateISO8601Len < CBMC_MAX_OBJECT_SIZE ); 46 | 47 | pDateISO8601 = malloc( dateISO8601Len ); 48 | 49 | status = SigV4_AwsIotDateToIso8601( pInputDate, dateLen, pDateISO8601, dateISO8601Len ); 50 | 51 | __CPROVER_assert( status == SigV4InvalidParameter || status == SigV4Success || status == SigV4ISOFormattingError, "This is not a valid SigV4 return status" ); 52 | } 53 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_AwsIotDateToIso8601/cbmc-proof.txt: -------------------------------------------------------------------------------- 1 | # This file marks this directory as containing a CBMC proof. 2 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_AwsIotDateToIso8601/cbmc-viewer.json: -------------------------------------------------------------------------------- 1 | { "expected-missing-functions": 2 | [ 3 | 4 | ], 5 | "proof-name": "SigV4_AwsIotDateToIso8601", 6 | "proof-root": "test/cbmc/proofs" 7 | } 8 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_GenerateHTTPAuthorization/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | HARNESS_ENTRY = harness 5 | HARNESS_FILE = SigV4_GenerateHTTPAuthorization_harness 6 | 7 | # This should be a unique identifier for this proof, and will appear on the 8 | # Litani dashboard. It can be human-readable and contain spaces if you wish. 9 | PROOF_UID = SigV4_GenerateHTTPAuthorization 10 | 11 | # Define constants so as to limit the running time of the proofs. 12 | # Note that these constants are also deliberately chosen so as to attain 13 | # coverage for the SigV4InsufficientMemory cases. 14 | # For the constants below, 15 | # SIGV4_PROCESSING_BUFFER_LENGTH is set specifically to 60. 16 | # It may be easier to attain coverage if the processing buffer is instead 17 | # provided by the user as the length can be variable. 18 | # However, since the length of the processing buffer is fixed, 19 | # these constants must also be fixed in order to match whatever 20 | # SIGV4_PROCESSING_BUFFER_LENGTH is set to in sigv4_config.h. 21 | MAX_QUERY_LEN=6 22 | MAX_HEADERS_LEN=6 23 | MAX_URI_LEN=3 24 | MAX_REQUEST_LEN=16 25 | S3_SERVICE_LEN=2 26 | UNSIGNED_PAYLOAD_LEN=17 27 | MAX_REGION_LEN=30 28 | MAX_SERVICE_LEN=30 29 | MAX_ALGORITHM_LEN=30 30 | MAX_HASH_DIGEST_LEN=16 31 | MAX_HASH_BLOCK_LEN=17 32 | # This is the actual maximum length of an AWS access key ID 33 | MAX_ACCESS_KEY_ID_LEN=128 34 | 35 | DEFINES += -DMAX_QUERY_LEN=$(MAX_QUERY_LEN) 36 | DEFINES += -DMAX_HEADERS_LEN=$(MAX_HEADERS_LEN) 37 | DEFINES += -DMAX_URI_LEN=$(MAX_URI_LEN) 38 | DEFINES += -DMAX_HASH_DIGEST_LEN=$(MAX_HASH_DIGEST_LEN) 39 | DEFINES += -DMAX_HASH_BLOCK_LEN=$(MAX_HASH_BLOCK_LEN) 40 | DEFINES += -DMAX_REGION_LEN=$(MAX_REGION_LEN) 41 | DEFINES += -DMAX_SERVICE_LEN=$(MAX_SERVICE_LEN) 42 | DEFINES += -DMAX_ALGORITHM_LEN=$(MAX_ALGORITHM_LEN) 43 | DEFINES += -DMAX_ACCESS_KEY_ID_LEN=$(MAX_ACCESS_KEY_ID_LEN) 44 | INCLUDES += 45 | 46 | REMOVE_FUNCTION_BODY += memcpy 47 | REMOVE_FUNCTION_BODY += memmove 48 | UNWINDSET += setQueryStringFieldsAndValues.0:$(MAX_QUERY_LEN) 49 | UNWINDSET += parseHeaderKeyValueEntries.0:$(MAX_HEADERS_LEN) 50 | UNWINDSET += lowercaseHexEncode.0:$(MAX_HASH_DIGEST_LEN) 51 | UNWINDSET += hmacIntermediate.0:$(MAX_HASH_BLOCK_LEN) 52 | UNWINDSET += hmacFinal.0:$(MAX_HASH_BLOCK_LEN) 53 | UNWINDSET += strncmp.0:$(S3_SERVICE_LEN) 54 | UNWINDSET += strlen.0:$(UNSIGNED_PAYLOAD_LEN) 55 | 56 | PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c 57 | PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/hash_stubs.c 58 | PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/memcpy.c 59 | PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/memmove.c 60 | PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/sigv4_stubs.c 61 | 62 | include ../Makefile-json.common 63 | 64 | # Substitution command to pass to sed for patching sigv4.c. The 65 | # characters " and # must be escaped with backslash. 66 | SIGV4_SED_EXPR = 1s/^/\#include \"sigv4_stubs.h\" /; s/^static //; s/SigV4Status_t (scanValue|SigV4_EncodeURI|generateCanonicalQuery|generateCanonicalAndSignedHeaders|copyHeaderStringToCanonicalBuffer)\b/&_/ 67 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_GenerateHTTPAuthorization/README.md: -------------------------------------------------------------------------------- 1 | SigV4_GenerateHTTPAuthorization proof 2 | ============== 3 | 4 | This directory contains a memory safety proof for SigV4_GenerateHTTPAuthorization. 5 | 6 | To run the proof. 7 | ------------- 8 | 9 | * Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer` 10 | to your path. 11 | * Run `make`. 12 | * Open html/index.html in a web browser. 13 | 14 | To use [`arpa`](https://awslabs.github.io/aws-proof-build-assistant) to simplify writing Makefiles. 15 | ------------- 16 | 17 | * Run `make arpa` to generate a Makefile.arpa that contains relevant build information for the proof. 18 | * Use Makefile.arpa as the starting point for your proof Makefile by: 19 | 1. Modifying Makefile.arpa (if required). 20 | 2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`). 21 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_GenerateHTTPAuthorization/SigV4_GenerateHTTPAuthorization_harness.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file SigV4_GenerateHTTPAuthorization_harness.c 27 | * @brief Implements the proof harness for the SigV4_GenerateHTTPAuthorization function. 28 | */ 29 | 30 | /* Include paths for public enums, structures, and macros. */ 31 | #include "stdlib.h" 32 | #include "sigv4.h" 33 | #include "sigv4_internal.h" 34 | #include "hash_stubs.h" 35 | 36 | void harness() 37 | { 38 | SigV4Parameters_t * pSigV4Params; 39 | SigV4HttpParameters_t * pHttpParams; 40 | SigV4CryptoInterface_t * pCryptoInterface; 41 | SigV4Credentials_t * pCredentials; 42 | char * pAuthBuf; 43 | size_t * authBufLen; 44 | char * pSignature; 45 | size_t signatureLen; 46 | SigV4Status_t status; 47 | 48 | pHttpParams = malloc( sizeof( SigV4HttpParameters_t ) ); 49 | pSigV4Params = malloc( sizeof( SigV4Parameters_t ) ); 50 | pCryptoInterface = malloc( sizeof( SigV4CryptoInterface_t ) ); 51 | pCredentials = malloc( sizeof( SigV4Credentials_t ) ); 52 | 53 | /* This property applies to all hash functions. */ 54 | if( pCryptoInterface != NULL ) 55 | { 56 | __CPROVER_assume( SIGV4_HMAC_SIGNING_KEY_PREFIX_LEN < pCryptoInterface->hashBlockLen && pCryptoInterface->hashBlockLen <= MAX_HASH_BLOCK_LEN ); 57 | __CPROVER_assume( 0U < pCryptoInterface->hashDigestLen && pCryptoInterface->hashDigestLen <= MAX_HASH_DIGEST_LEN ); 58 | __CPROVER_assume( pCryptoInterface->hashDigestLen <= pCryptoInterface->hashBlockLen ); 59 | pCryptoInterface->hashInit = nondet_bool() ? NULL : HashInitStub; 60 | pCryptoInterface->hashUpdate = nondet_bool() ? NULL : HashUpdateStub; 61 | pCryptoInterface->hashFinal = nondet_bool() ? NULL : HashFinalStub; 62 | } 63 | 64 | if( pCredentials != NULL ) 65 | { 66 | /* Make size assumptions for string-like types. */ 67 | __CPROVER_assume( pCredentials->accessKeyIdLen <= MAX_ACCESS_KEY_ID_LEN ); 68 | __CPROVER_assume( pCredentials->secretAccessKeyLen < CBMC_MAX_OBJECT_SIZE ); 69 | pCredentials->pAccessKeyId = malloc( pCredentials->accessKeyIdLen ); 70 | pCredentials->pSecretAccessKey = malloc( pCredentials->secretAccessKeyLen ); 71 | } 72 | 73 | if( pHttpParams != NULL ) 74 | { 75 | /* Make size assumptions for string-like types. */ 76 | __CPROVER_assume( pHttpParams->payloadLen < CBMC_MAX_OBJECT_SIZE ); 77 | __CPROVER_assume( pHttpParams->httpMethodLen < CBMC_MAX_OBJECT_SIZE ); 78 | __CPROVER_assume( pHttpParams->pathLen < MAX_URI_LEN ); 79 | __CPROVER_assume( pHttpParams->queryLen < MAX_QUERY_LEN ); 80 | __CPROVER_assume( pHttpParams->headersLen < MAX_HEADERS_LEN ); 81 | pHttpParams->pPayload = malloc( pHttpParams->payloadLen ); 82 | pHttpParams->pHttpMethod = malloc( pHttpParams->httpMethodLen ); 83 | pHttpParams->pPath = malloc( pHttpParams->pathLen ); 84 | pHttpParams->pQuery = malloc( pHttpParams->queryLen ); 85 | pHttpParams->pHeaders = malloc( pHttpParams->headersLen ); 86 | } 87 | 88 | if( pSigV4Params != NULL ) 89 | { 90 | /* Make size assumptions for string-like types. */ 91 | __CPROVER_assume( pSigV4Params->regionLen < MAX_REGION_LEN ); 92 | __CPROVER_assume( pSigV4Params->serviceLen < MAX_SERVICE_LEN ); 93 | __CPROVER_assume( pSigV4Params->algorithmLen < MAX_ALGORITHM_LEN ); 94 | pSigV4Params->pRegion = malloc( pSigV4Params->regionLen ); 95 | pSigV4Params->pService = malloc( pSigV4Params->serviceLen ); 96 | pSigV4Params->pAlgorithm = malloc( pSigV4Params->algorithmLen ); 97 | 98 | /* The ISO date has a fixed length. */ 99 | pSigV4Params->pDateIso8601 = malloc( SIGV4_ISO_STRING_LEN ); 100 | 101 | /* Set other structs within SigV4Parameters_t. */ 102 | pSigV4Params->pCredentials = pCredentials; 103 | pSigV4Params->pCryptoInterface = pCryptoInterface; 104 | pSigV4Params->pHttpParameters = pHttpParams; 105 | } 106 | 107 | authBufLen = malloc( sizeof( size_t ) ); 108 | 109 | if( authBufLen != NULL ) 110 | { 111 | __CPROVER_assume( *authBufLen < CBMC_MAX_OBJECT_SIZE ); 112 | pAuthBuf = malloc( *authBufLen ); 113 | } 114 | 115 | status = SigV4_GenerateHTTPAuthorization( pSigV4Params, 116 | pAuthBuf, 117 | authBufLen, 118 | nondet_bool() ? NULL : &pSignature, 119 | nondet_bool() ? NULL : &signatureLen ); 120 | __CPROVER_assert( status == SigV4InvalidParameter || status == SigV4Success || status == SigV4HashError || status == SigV4InsufficientMemory || status == SigV4MaxHeaderPairCountExceeded || status == SigV4MaxQueryPairCountExceeded, "This is not a valid SigV4 return status" ); 121 | 122 | if( status == SigV4Success ) 123 | { 124 | /* The signature must start at a location within pAuthBuf and 125 | * should not end past the length of pAuthBuf. */ 126 | __CPROVER_assert( pAuthBuf <= pSignature, 127 | "Signature does not start at a location within pAuthBuf." ); 128 | __CPROVER_assert( pSignature + signatureLen <= pAuthBuf + *authBufLen, 129 | "Signature ends past the length of pAuthBuf." ); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_GenerateHTTPAuthorization/cbmc-proof.txt: -------------------------------------------------------------------------------- 1 | # This file marks this directory as containing a CBMC proof. 2 | -------------------------------------------------------------------------------- /test/cbmc/proofs/SigV4_GenerateHTTPAuthorization/cbmc-viewer.json: -------------------------------------------------------------------------------- 1 | { "expected-missing-functions": 2 | [ 3 | 4 | ], 5 | "proof-name": "SigV4_GenerateHTTPAuthorization", 6 | "proof-root": "test/cbmc/proofs" 7 | } 8 | -------------------------------------------------------------------------------- /test/cbmc/proofs/copyHeaderStringToCanonicalBuffer/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | HARNESS_ENTRY = harness 5 | HARNESS_FILE = copyHeaderStringToCanonicalBuffer_harness 6 | 7 | # This should be a unique identifier for this proof, and will appear on the 8 | # Litani dashboard. It can be human-readable and contain spaces if you wish. 9 | PROOF_UID = copyHeaderStringToCanonicalBuffer 10 | 11 | # This value was experimentally chosen to provide 100% coverage 12 | # without tripping unwinding assertions and without exhausting memory. 13 | CBMC_MAX_BUFSIZE=10 14 | MAX_HASH_BLOCK_LEN=17 15 | MAX_HASH_DIGEST_LEN=16 16 | 17 | DEFINES += -DMAX_HASH_BLOCK_LEN=$(MAX_HASH_BLOCK_LEN) 18 | DEFINES += -DCBMC_MAX_BUFSIZE=$(CBMC_MAX_BUFSIZE) 19 | DEFINES += -DMAX_HASH_DIGEST_LEN=$(MAX_HASH_DIGEST_LEN) 20 | INCLUDES += 21 | 22 | REMOVE_FUNCTION_BODY += 23 | UNWINDSET +=copyHeaderStringToCanonicalBuffer.0:$(CBMC_MAX_BUFSIZE) 24 | 25 | PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c 26 | 27 | # If this proof is found to consume huge amounts of RAM, you can set the 28 | # EXPENSIVE variable. With new enough versions of the proof tools, this will 29 | # restrict the number of EXPENSIVE CBMC jobs running at once. See the 30 | # documentation in Makefile.common under the "Job Pools" heading for details. 31 | # EXPENSIVE = true 32 | 33 | include ../Makefile-json.common 34 | 35 | # Substitution command to pass to sed for patching sigv4.c. The 36 | # characters " and # must be escaped with backslash. 37 | SIGV4_SED_EXPR = s/^static // 38 | -------------------------------------------------------------------------------- /test/cbmc/proofs/copyHeaderStringToCanonicalBuffer/README.md: -------------------------------------------------------------------------------- 1 | copyHeaderStringToCanonicalBuffer proof 2 | ============== 3 | 4 | This directory contains a memory safety proof for copyHeaderStringToCanonicalBuffer. 5 | 6 | To run the proof. 7 | ------------- 8 | 9 | * Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer` 10 | to your path. 11 | * Run `make`. 12 | * Open html/index.html in a web browser. -------------------------------------------------------------------------------- /test/cbmc/proofs/copyHeaderStringToCanonicalBuffer/cbmc-proof.txt: -------------------------------------------------------------------------------- 1 | # This file marks this directory as containing a CBMC proof. 2 | -------------------------------------------------------------------------------- /test/cbmc/proofs/copyHeaderStringToCanonicalBuffer/cbmc-viewer.json: -------------------------------------------------------------------------------- 1 | { "expected-missing-functions": 2 | [ 3 | 4 | ], 5 | "proof-name": "copyHeaderStringToCanonicalBuffer", 6 | "proof-root": "test/cbmc/proofs" 7 | } 8 | -------------------------------------------------------------------------------- /test/cbmc/proofs/copyHeaderStringToCanonicalBuffer/copyHeaderStringToCanonicalBuffer_harness.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file copyHeaderStringToCanonicalBuffer_harness.c 27 | * @brief Implements the proof harness for copyHeaderStringToCanonicalBuffer function. 28 | */ 29 | #include "stdlib.h" 30 | #include "sigv4_annex.h" 31 | 32 | void harness() 33 | { 34 | const char * pData; 35 | size_t dataLen; 36 | uint32_t flags; 37 | char separator; 38 | CanonicalContext_t * canonicalRequest; 39 | SigV4Status_t sigv4Status; 40 | 41 | canonicalRequest = malloc( sizeof( CanonicalContext_t ) ); 42 | 43 | __CPROVER_assume( canonicalRequest != NULL ); 44 | 45 | 46 | /* The data to be written is assumed to start at a location within the processing 47 | * buffer and should not end past the length of the processing buffer. */ 48 | size_t bytesConsumed; 49 | 50 | __CPROVER_assume( canonicalRequest->bufRemaining < SIGV4_PROCESSING_BUFFER_LENGTH ); 51 | bytesConsumed = SIGV4_PROCESSING_BUFFER_LENGTH - canonicalRequest->bufRemaining; 52 | __CPROVER_assume( dataLen > 0U && dataLen < CBMC_MAX_BUFSIZE ); 53 | canonicalRequest->uxCursorIndex = bytesConsumed; 54 | 55 | pData = malloc( dataLen ); 56 | 57 | __CPROVER_assume( pData != NULL ); 58 | 59 | sigv4Status = copyHeaderStringToCanonicalBuffer( pData, dataLen, flags, separator, canonicalRequest ); 60 | 61 | __CPROVER_assert( ( sigv4Status == SigV4InvalidParameter || sigv4Status == SigV4Success || sigv4Status == SigV4InsufficientMemory ), "This is not a valid SIGV4 Status." ); 62 | } 63 | -------------------------------------------------------------------------------- /test/cbmc/proofs/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/SigV4-for-AWS-IoT-embedded-sdk/892bcbb2d4b95daf2b7306ba3210e74b25bfae16/test/cbmc/proofs/lib/__init__.py -------------------------------------------------------------------------------- /test/cbmc/proofs/lib/print_tool_versions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | 7 | import logging 8 | import pathlib 9 | import shutil 10 | import subprocess 11 | 12 | 13 | _TOOLS = [ 14 | "cadical", 15 | "cbmc", 16 | "cbmc-viewer", 17 | "cbmc-starter-kit-update", 18 | "kissat", 19 | "litani", 20 | ] 21 | 22 | 23 | def _format_versions(table): 24 | lines = [ 25 | "", 26 | '', 27 | ] 28 | for tool, version in table.items(): 29 | if version: 30 | v_str = f'
{version}
' 31 | else: 32 | v_str = 'not found' 33 | lines.append( 34 | f'' 36 | f'') 37 | lines.append("
Tool Versions
{tool}:{v_str}
") 38 | return "\n".join(lines) 39 | 40 | 41 | def _get_tool_versions(): 42 | ret = {} 43 | for tool in _TOOLS: 44 | err = f"Could not determine version of {tool}: " 45 | ret[tool] = None 46 | if not shutil.which(tool): 47 | logging.error("%s'%s' not found on $PATH", err, tool) 48 | continue 49 | cmd = [tool, "--version"] 50 | proc = subprocess.Popen(cmd, text=True, stdout=subprocess.PIPE) 51 | try: 52 | out, _ = proc.communicate(timeout=10) 53 | except subprocess.TimeoutExpired: 54 | logging.error("%s'%s --version' timed out", err, tool) 55 | continue 56 | if proc.returncode: 57 | logging.error( 58 | "%s'%s --version' returned %s", err, tool, str(proc.returncode)) 59 | continue 60 | ret[tool] = out.strip() 61 | return ret 62 | 63 | 64 | def main(): 65 | exe_name = pathlib.Path(__file__).name 66 | logging.basicConfig(format=f"{exe_name}: %(message)s") 67 | 68 | table = _get_tool_versions() 69 | out = _format_versions(table) 70 | print(out) 71 | 72 | 73 | if __name__ == "__main__": 74 | main() 75 | -------------------------------------------------------------------------------- /test/cbmc/proofs/lib/summarize.py: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: MIT-0 3 | 4 | import argparse 5 | import json 6 | import logging 7 | import os 8 | import sys 9 | 10 | 11 | DESCRIPTION = """Print 2 tables in GitHub-flavored Markdown that summarize 12 | an execution of CBMC proofs.""" 13 | 14 | 15 | def get_args(): 16 | """Parse arguments for summarize script.""" 17 | parser = argparse.ArgumentParser(description=DESCRIPTION) 18 | for arg in [{ 19 | "flags": ["--run-file"], 20 | "help": "path to the Litani run.json file", 21 | "required": True, 22 | }]: 23 | flags = arg.pop("flags") 24 | parser.add_argument(*flags, **arg) 25 | return parser.parse_args() 26 | 27 | 28 | def _get_max_length_per_column_list(data): 29 | ret = [len(item) + 1 for item in data[0]] 30 | for row in data[1:]: 31 | for idx, item in enumerate(row): 32 | ret[idx] = max(ret[idx], len(item) + 1) 33 | return ret 34 | 35 | 36 | def _get_table_header_separator(max_length_per_column_list): 37 | line_sep = "" 38 | for max_length_of_word_in_col in max_length_per_column_list: 39 | line_sep += "|" + "-" * (max_length_of_word_in_col + 1) 40 | line_sep += "|\n" 41 | return line_sep 42 | 43 | 44 | def _get_entries(max_length_per_column_list, row_data): 45 | entries = [] 46 | for row in row_data: 47 | entry = "" 48 | for idx, word in enumerate(row): 49 | max_length_of_word_in_col = max_length_per_column_list[idx] 50 | space_formatted_word = (max_length_of_word_in_col - len(word)) * " " 51 | entry += "| " + word + space_formatted_word 52 | entry += "|\n" 53 | entries.append(entry) 54 | return entries 55 | 56 | 57 | def _get_rendered_table(data): 58 | table = [] 59 | max_length_per_column_list = _get_max_length_per_column_list(data) 60 | entries = _get_entries(max_length_per_column_list, data) 61 | for idx, entry in enumerate(entries): 62 | if idx == 1: 63 | line_sep = _get_table_header_separator(max_length_per_column_list) 64 | table.append(line_sep) 65 | table.append(entry) 66 | table.append("\n") 67 | return "".join(table) 68 | 69 | 70 | def _get_status_and_proof_summaries(run_dict): 71 | """Parse a dict representing a Litani run and create lists summarizing the 72 | proof results. 73 | 74 | Parameters 75 | ---------- 76 | run_dict 77 | A dictionary representing a Litani run. 78 | 79 | 80 | Returns 81 | ------- 82 | A list of 2 lists. 83 | The first sub-list maps a status to the number of proofs with that status. 84 | The second sub-list maps each proof to its status. 85 | """ 86 | count_statuses = {} 87 | proofs = [["Proof", "Status"]] 88 | for proof_pipeline in run_dict["pipelines"]: 89 | status_pretty_name = proof_pipeline["status"].title().replace("_", " ") 90 | try: 91 | count_statuses[status_pretty_name] += 1 92 | except KeyError: 93 | count_statuses[status_pretty_name] = 1 94 | if proof_pipeline["name"] == "print_tool_versions": 95 | continue 96 | proofs.append([proof_pipeline["name"], status_pretty_name]) 97 | statuses = [["Status", "Count"]] 98 | for status, count in count_statuses.items(): 99 | statuses.append([status, str(count)]) 100 | return [statuses, proofs] 101 | 102 | 103 | def print_proof_results(out_file): 104 | """ 105 | Print 2 strings that summarize the proof results. 106 | When printing, each string will render as a GitHub flavored Markdown table. 107 | """ 108 | output = "## Summary of CBMC proof results\n\n" 109 | with open(out_file, encoding='utf-8') as run_json: 110 | run_dict = json.load(run_json) 111 | status_table, proof_table = _get_status_and_proof_summaries(run_dict) 112 | for summary in (status_table, proof_table): 113 | output += _get_rendered_table(summary) 114 | 115 | print(output) 116 | sys.stdout.flush() 117 | 118 | github_summary_file = os.getenv("GITHUB_STEP_SUMMARY") 119 | if github_summary_file: 120 | with open(github_summary_file, "a") as handle: 121 | print(output, file=handle) 122 | handle.flush() 123 | else: 124 | logging.warning( 125 | "$GITHUB_STEP_SUMMARY not set, not writing summary file") 126 | 127 | msg = ( 128 | "Click the 'Summary' button to view a Markdown table " 129 | "summarizing all proof results") 130 | if run_dict["status"] != "success": 131 | logging.error("Not all proofs passed.") 132 | logging.error(msg) 133 | sys.exit(1) 134 | logging.info(msg) 135 | 136 | 137 | if __name__ == '__main__': 138 | args = get_args() 139 | logging.basicConfig(format="%(levelname)s: %(message)s") 140 | try: 141 | print_proof_results(args.run_file) 142 | except Exception as ex: # pylint: disable=broad-except 143 | logging.critical("Could not print results. Exception: %s", str(ex)) 144 | -------------------------------------------------------------------------------- /test/cbmc/proofs/run-cbmc-proofs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | # SPDX-License-Identifier: MIT-0 5 | 6 | 7 | import argparse 8 | import asyncio 9 | import json 10 | import logging 11 | import math 12 | import os 13 | import pathlib 14 | import re 15 | import subprocess 16 | import sys 17 | import tempfile 18 | 19 | from lib.summarize import print_proof_results 20 | 21 | 22 | DESCRIPTION = "Configure and run all CBMC proofs in parallel" 23 | 24 | # Keep the epilog hard-wrapped at 70 characters, as it gets printed 25 | # verbatim in the terminal. 70 characters stops here --------------> | 26 | EPILOG = """ 27 | This tool automates the process of running `make report` in each of 28 | the CBMC proof directories. The tool calculates the dependency graph 29 | of all tasks needed to build, run, and report on all the proofs, and 30 | executes these tasks in parallel. 31 | 32 | The tool is roughly equivalent to doing this: 33 | 34 | litani init --project "my-cool-project"; 35 | 36 | find . -name cbmc-proof.txt | while read -r proof; do 37 | pushd $(dirname ${proof}); 38 | 39 | # The `make _report` rule adds a single proof to litani 40 | # without running it 41 | make _report; 42 | 43 | popd; 44 | done 45 | 46 | litani run-build; 47 | 48 | except that it is much faster and provides some convenience options. 49 | The CBMC CI runs this script with no arguments to build and run all 50 | proofs in parallel. The value of "my-cool-project" is taken from the 51 | PROJECT_NAME variable in Makefile-project-defines. 52 | 53 | The --no-standalone argument omits the `litani init` and `litani 54 | run-build`; use it when you want to add additional proof jobs, not 55 | just the CBMC ones. In that case, you would run `litani init` 56 | yourself; then run `run-cbmc-proofs --no-standalone`; add any 57 | additional jobs that you want to execute with `litani add-job`; and 58 | finally run `litani run-build`. 59 | 60 | The litani dashboard will be written under the `output` directory; the 61 | cbmc-viewer reports remain in the `$PROOF_DIR/report` directory. The 62 | HTML dashboard from the latest Litani run will always be symlinked to 63 | `output/latest/html/index.html`, so you can keep that page open in 64 | your browser and reload the page whenever you re-run this script. 65 | """ 66 | # 70 characters stops here ----------------------------------------> | 67 | 68 | 69 | def get_project_name(): 70 | cmd = [ 71 | "make", 72 | "--no-print-directory", 73 | "-f", "Makefile.common", 74 | "echo-project-name", 75 | ] 76 | logging.debug(" ".join(cmd)) 77 | proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False) 78 | if proc.returncode: 79 | logging.critical("could not run make to determine project name") 80 | sys.exit(1) 81 | if not proc.stdout.strip(): 82 | logging.warning( 83 | "project name has not been set; using generic name instead. " 84 | "Set the PROJECT_NAME value in Makefile-project-defines to " 85 | "remove this warning") 86 | return "" 87 | return proc.stdout.strip() 88 | 89 | 90 | def get_args(): 91 | pars = argparse.ArgumentParser( 92 | description=DESCRIPTION, epilog=EPILOG, 93 | formatter_class=argparse.RawDescriptionHelpFormatter) 94 | for arg in [{ 95 | "flags": ["-j", "--parallel-jobs"], 96 | "type": int, 97 | "metavar": "N", 98 | "help": "run at most N proof jobs in parallel", 99 | }, { 100 | "flags": ["--fail-on-proof-failure"], 101 | "action": "store_true", 102 | "help": "exit with return code `10' if any proof failed" 103 | " (default: exit 0)", 104 | }, { 105 | "flags": ["--no-standalone"], 106 | "action": "store_true", 107 | "help": "only configure proofs: do not initialize nor run", 108 | }, { 109 | "flags": ["-p", "--proofs"], 110 | "nargs": "+", 111 | "metavar": "DIR", 112 | "help": "only run proof in directory DIR (can pass more than one)", 113 | }, { 114 | "flags": ["--project-name"], 115 | "metavar": "NAME", 116 | "default": get_project_name(), 117 | "help": "project name for report. Default: %(default)s", 118 | }, { 119 | "flags": ["--marker-file"], 120 | "metavar": "FILE", 121 | "default": "cbmc-proof.txt", 122 | "help": ( 123 | "name of file that marks proof directories. Default: " 124 | "%(default)s"), 125 | }, { 126 | "flags": ["--no-memory-profile"], 127 | "action": "store_true", 128 | "help": "disable memory profiling, even if Litani supports it" 129 | }, { 130 | "flags": ["--no-expensive-limit"], 131 | "action": "store_true", 132 | "help": "do not limit parallelism of 'EXPENSIVE' jobs", 133 | }, { 134 | "flags": ["--expensive-jobs-parallelism"], 135 | "metavar": "N", 136 | "default": 1, 137 | "type": int, 138 | "help": ( 139 | "how many proof jobs marked 'EXPENSIVE' to run in parallel. " 140 | "Default: %(default)s"), 141 | }, { 142 | "flags": ["--verbose"], 143 | "action": "store_true", 144 | "help": "verbose output", 145 | }, { 146 | "flags": ["--debug"], 147 | "action": "store_true", 148 | "help": "debug output", 149 | }, { 150 | "flags": ["--summarize"], 151 | "action": "store_true", 152 | "help": "summarize proof results with two tables on stdout", 153 | }, { 154 | "flags": ["--version"], 155 | "action": "version", 156 | "version": "CBMC starter kit 2.5", 157 | "help": "display version and exit" 158 | }]: 159 | flags = arg.pop("flags") 160 | pars.add_argument(*flags, **arg) 161 | return pars.parse_args() 162 | 163 | 164 | def set_up_logging(verbose): 165 | if verbose: 166 | level = logging.DEBUG 167 | else: 168 | level = logging.WARNING 169 | logging.basicConfig( 170 | format="run-cbmc-proofs: %(message)s", level=level) 171 | 172 | 173 | def task_pool_size(): 174 | ret = os.cpu_count() 175 | if ret is None or ret < 3: 176 | return 1 177 | return ret - 2 178 | 179 | 180 | def print_counter(counter): 181 | # pylint: disable=consider-using-f-string 182 | print("\rConfiguring CBMC proofs: " 183 | "{complete:{width}} / {total:{width}}".format(**counter), end="", file=sys.stderr) 184 | 185 | 186 | def get_proof_dirs(proof_root, proof_list, marker_file): 187 | if proof_list is not None: 188 | proofs_remaining = list(proof_list) 189 | else: 190 | proofs_remaining = [] 191 | 192 | for root, _, fyles in os.walk(proof_root): 193 | proof_name = str(pathlib.Path(root).name) 194 | if root != str(proof_root) and ".litani_cache_dir" in fyles: 195 | pathlib.Path(f"{root}/.litani_cache_dir").unlink() 196 | if proof_list and proof_name not in proof_list: 197 | continue 198 | if proof_list and proof_name in proofs_remaining: 199 | proofs_remaining.remove(proof_name) 200 | if marker_file in fyles: 201 | yield root 202 | 203 | if proofs_remaining: 204 | logging.critical( 205 | "The following proofs were not found: %s", 206 | ", ".join(proofs_remaining)) 207 | sys.exit(1) 208 | 209 | 210 | def run_build(litani, jobs, fail_on_proof_failure, summarize): 211 | cmd = [str(litani), "run-build"] 212 | if jobs: 213 | cmd.extend(["-j", str(jobs)]) 214 | if fail_on_proof_failure: 215 | cmd.append("--fail-on-pipeline-failure") 216 | if summarize: 217 | out_file = pathlib.Path(tempfile.gettempdir(), "run.json").resolve() 218 | cmd.extend(["--out-file", str(out_file)]) 219 | 220 | logging.debug(" ".join(cmd)) 221 | proc = subprocess.run(cmd, check=False) 222 | 223 | if proc.returncode and not fail_on_proof_failure: 224 | logging.critical("Failed to run litani run-build") 225 | sys.exit(1) 226 | 227 | if summarize: 228 | print_proof_results(out_file) 229 | out_file.unlink() 230 | 231 | if proc.returncode: 232 | logging.error("One or more proofs failed") 233 | sys.exit(10) 234 | 235 | def get_litani_path(proof_root): 236 | cmd = [ 237 | "make", 238 | "--no-print-directory", 239 | f"PROOF_ROOT={proof_root}", 240 | "-f", "Makefile.common", 241 | "litani-path", 242 | ] 243 | logging.debug(" ".join(cmd)) 244 | proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False) 245 | if proc.returncode: 246 | logging.critical("Could not determine path to litani") 247 | sys.exit(1) 248 | return proc.stdout.strip() 249 | 250 | 251 | def get_litani_capabilities(litani_path): 252 | cmd = [litani_path, "print-capabilities"] 253 | proc = subprocess.run( 254 | cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False) 255 | if proc.returncode: 256 | return [] 257 | try: 258 | return json.loads(proc.stdout) 259 | except RuntimeError: 260 | logging.warning("Could not load litani capabilities: '%s'", proc.stdout) 261 | return [] 262 | 263 | 264 | def check_uid_uniqueness(proof_dir, proof_uids): 265 | with (pathlib.Path(proof_dir) / "Makefile").open() as handle: 266 | for line in handle: 267 | match = re.match(r"^PROOF_UID\s*=\s*(?P\w+)", line) 268 | if not match: 269 | continue 270 | if match["uid"] not in proof_uids: 271 | proof_uids[match["uid"]] = proof_dir 272 | return 273 | 274 | logging.critical( 275 | "The Makefile in directory '%s' should have a different " 276 | "PROOF_UID than the Makefile in directory '%s'", 277 | proof_dir, proof_uids[match["uid"]]) 278 | sys.exit(1) 279 | 280 | logging.critical( 281 | "The Makefile in directory '%s' should contain a line like", proof_dir) 282 | logging.critical("PROOF_UID = ...") 283 | logging.critical("with a unique identifier for the proof.") 284 | sys.exit(1) 285 | 286 | 287 | def should_enable_memory_profiling(litani_caps, args): 288 | if args.no_memory_profile: 289 | return False 290 | return "memory_profile" in litani_caps 291 | 292 | 293 | def should_enable_pools(litani_caps, args): 294 | if args.no_expensive_limit: 295 | return False 296 | return "pools" in litani_caps 297 | 298 | 299 | async def configure_proof_dirs( # pylint: disable=too-many-arguments 300 | queue, counter, proof_uids, enable_pools, enable_memory_profiling, debug): 301 | while True: 302 | print_counter(counter) 303 | path = str(await queue.get()) 304 | 305 | check_uid_uniqueness(path, proof_uids) 306 | 307 | pools = ["ENABLE_POOLS=true"] if enable_pools else [] 308 | profiling = [ 309 | "ENABLE_MEMORY_PROFILING=true"] if enable_memory_profiling else [] 310 | 311 | # Allow interactive tasks to preempt proof configuration 312 | proc = await asyncio.create_subprocess_exec( 313 | "nice", "-n", "15", "make", *pools, 314 | *profiling, "-B", "_report", "" if debug else "--quiet", cwd=path, 315 | stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 316 | stdout, stderr = await proc.communicate() 317 | logging.debug("returncode: %s", str(proc.returncode)) 318 | logging.debug("stdout:") 319 | for line in stdout.decode().splitlines(): 320 | logging.debug(line) 321 | logging.debug("stderr:") 322 | for line in stderr.decode().splitlines(): 323 | logging.debug(line) 324 | 325 | counter["fail" if proc.returncode else "pass"].append(path) 326 | counter["complete"] += 1 327 | 328 | print_counter(counter) 329 | queue.task_done() 330 | 331 | 332 | async def main(): # pylint: disable=too-many-locals 333 | args = get_args() 334 | set_up_logging(args.verbose) 335 | 336 | proof_root = pathlib.Path(os.getcwd()) 337 | litani = get_litani_path(proof_root) 338 | 339 | litani_caps = get_litani_capabilities(litani) 340 | enable_pools = should_enable_pools(litani_caps, args) 341 | init_pools = [ 342 | "--pools", f"expensive:{args.expensive_jobs_parallelism}" 343 | ] if enable_pools else [] 344 | 345 | if not args.no_standalone: 346 | cmd = [ 347 | str(litani), "init", *init_pools, "--project", args.project_name, 348 | "--no-print-out-dir", 349 | ] 350 | 351 | if "output_directory_flags" in litani_caps: 352 | out_prefix = proof_root / "output" 353 | out_symlink = out_prefix / "latest" 354 | out_index = out_symlink / "html" / "index.html" 355 | cmd.extend([ 356 | "--output-prefix", str(out_prefix), 357 | "--output-symlink", str(out_symlink), 358 | ]) 359 | print( 360 | "\nFor your convenience, the output of this run will be symbolically linked to ", 361 | out_index, "\n") 362 | 363 | logging.debug(" ".join(cmd)) 364 | proc = subprocess.run(cmd, check=False) 365 | if proc.returncode: 366 | logging.critical("Failed to run litani init") 367 | sys.exit(1) 368 | 369 | proof_dirs = list(get_proof_dirs( 370 | proof_root, args.proofs, args.marker_file)) 371 | if not proof_dirs: 372 | logging.critical("No proof directories found") 373 | sys.exit(1) 374 | 375 | proof_queue = asyncio.Queue() 376 | for proof_dir in proof_dirs: 377 | proof_queue.put_nowait(proof_dir) 378 | 379 | counter = { 380 | "pass": [], 381 | "fail": [], 382 | "complete": 0, 383 | "total": len(proof_dirs), 384 | "width": int(math.log10(len(proof_dirs))) + 1 385 | } 386 | 387 | proof_uids = {} 388 | tasks = [] 389 | 390 | enable_memory_profiling = should_enable_memory_profiling(litani_caps, args) 391 | 392 | for _ in range(task_pool_size()): 393 | task = asyncio.create_task(configure_proof_dirs( 394 | proof_queue, counter, proof_uids, enable_pools, 395 | enable_memory_profiling, args.debug)) 396 | tasks.append(task) 397 | 398 | await proof_queue.join() 399 | 400 | print_counter(counter) 401 | print("", file=sys.stderr) 402 | 403 | if counter["fail"]: 404 | logging.critical( 405 | "Failed to configure the following proofs:\n%s", "\n".join( 406 | [str(f) for f in counter["fail"]])) 407 | sys.exit(1) 408 | 409 | if not args.no_standalone: 410 | run_build(litani, args.parallel_jobs, args.fail_on_proof_failure, args.summarize) 411 | 412 | 413 | if __name__ == "__main__": 414 | asyncio.run(main()) 415 | -------------------------------------------------------------------------------- /test/cbmc/sources/README.md: -------------------------------------------------------------------------------- 1 | CBMC proof source code 2 | ====================== 3 | 4 | This directory contains source code written for CBMC proofs. It is 5 | common to write some code to model aspects of the system under test, 6 | and this code goes here. 7 | -------------------------------------------------------------------------------- /test/cbmc/stubs/README.md: -------------------------------------------------------------------------------- 1 | CBMC proof stubs 2 | ====================== 3 | 4 | This directory contains the stubs written for CBMC proofs. It is 5 | common to stub out functionality like network send and receive methods 6 | when writing a CBMC proof, and the code for these stubs goes here. 7 | -------------------------------------------------------------------------------- /test/cbmc/stubs/hash_stubs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file hash_stubs.c 27 | * @brief Declarations for stubs used in sigv4.c. 28 | * Please see sigv4.c for documentation. 29 | */ 30 | 31 | /* Standard includes. */ 32 | #include "hash_stubs.h" 33 | 34 | int32_t HashInitStub( void * pHashContext ) 35 | { 36 | int32_t ret; 37 | 38 | return ret; 39 | } 40 | 41 | int32_t HashUpdateStub( void * pHashContext, 42 | const char * pInput, 43 | size_t inputLen ) 44 | { 45 | int32_t ret; 46 | 47 | return ret; 48 | } 49 | 50 | int32_t HashFinalStub( void * pHashContext, 51 | const char * pInput, 52 | size_t inputLen ) 53 | { 54 | int32_t ret; 55 | 56 | return ret; 57 | } 58 | -------------------------------------------------------------------------------- /test/cbmc/stubs/memcpy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file memcpy.c 27 | * @brief A stub for memcpy so that the proofs for functions that call memcpy 28 | * run much faster. 29 | */ 30 | 31 | #include 32 | 33 | /* This is a clang macro not available on linux */ 34 | #ifndef __has_builtin 35 | #define __has_builtin( x ) 0 36 | #endif 37 | 38 | #if __has_builtin( __builtin___memcpy_chk ) 39 | void * __builtin___memcpy_chk( void * dest, 40 | const void * src, 41 | size_t n, 42 | size_t m ) 43 | { 44 | /* Attempting to read or write 0 bytes will make __CPROVER_r/w_ok 45 | * fail. However, per ANSI C specification, memcpy must be able 46 | * to handle a copy length of zero. */ 47 | __CPROVER_assert( ( n == 0 ) || __CPROVER_w_ok( dest, n ), "write" ); 48 | __CPROVER_assert( ( n == 0 ) || __CPROVER_r_ok( src, n ), "read" ); 49 | return dest; 50 | } 51 | #else /* if __has_builtin( __builtin___memcpy_chk ) */ 52 | void * memcpy( void * dest, 53 | const void * src, 54 | size_t n ) 55 | { 56 | /* Per ANSI C specification, memcpy must be able to handle a copy length 57 | * of zero. */ 58 | __CPROVER_assert( ( n == 0 ) || __CPROVER_w_ok( dest, n ), "write" ); 59 | __CPROVER_assert( ( n == 0 ) || __CPROVER_r_ok( src, n ), "read" ); 60 | return dest; 61 | } 62 | #endif /* if __has_builtin( __builtin___memcpy_chk ) */ 63 | -------------------------------------------------------------------------------- /test/cbmc/stubs/memmove.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file memmove.c 27 | * @brief A stub for memmove so that the proofs for functions that call 28 | * memmove run much faster. 29 | */ 30 | 31 | #include 32 | 33 | /* This is a clang macro not available on linux */ 34 | #ifndef __has_builtin 35 | #define __has_builtin( x ) 0 36 | #endif 37 | 38 | #if __has_builtin( __builtin___memmove_chk ) 39 | void * __builtin___memmove_chk( void * dest, 40 | const void * src, 41 | size_t n, 42 | size_t m ) 43 | { 44 | /* Attempting to read or write 0 bytes will make __CPROVER_r/w_ok 45 | * fail. However, per ANSI C specification, memcpy must be able 46 | * to handle a copy length of zero. */ 47 | __CPROVER_assert( ( n == 0 ) || __CPROVER_w_ok( dest, n ), "write" ); 48 | __CPROVER_assert( ( n == 0 ) || __CPROVER_r_ok( src, n ), "read" ); 49 | return dest; 50 | } 51 | #else /* if __has_builtin( __builtin___memmove_chk ) */ 52 | void * memmove( void * dest, 53 | const void * src, 54 | size_t n ) 55 | { 56 | __CPROVER_assert( __CPROVER_w_ok( dest, n ), "write" ); 57 | __CPROVER_assert( __CPROVER_r_ok( src, n ), "read" ); 58 | return dest; 59 | } 60 | #endif /* if __has_builtin( __builtin___memmove_chk ) */ 61 | -------------------------------------------------------------------------------- /test/cbmc/stubs/sigv4_stubs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_stubs.c 27 | * @brief Implements the functions declared in sigv4_stubs.h 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | SigV4Status_t scanValue( const char * pDate, 35 | const char formatChar, 36 | size_t readLoc, 37 | size_t lenToRead, 38 | SigV4DateTime_t * pDateElements ) 39 | { 40 | SigV4Status_t returnStatus = SigV4InvalidParameter; 41 | const char * pMonthNames[] = MONTH_NAMES; 42 | const char * pLoc = pDate + readLoc; 43 | size_t remainingLenToRead = lenToRead; 44 | int32_t result = 0; 45 | static flag = 0; 46 | 47 | assert( pDate != NULL ); 48 | assert( pDateElements != NULL ); 49 | 50 | if( formatChar == '*' ) 51 | { 52 | remainingLenToRead = 0U; 53 | } 54 | 55 | /* Determine if month value is non-numeric. */ 56 | if( ( formatChar == 'M' ) && ( remainingLenToRead == MONTH_ASCII_LEN ) ) 57 | { 58 | returnStatus = SigV4Success; 59 | 60 | remainingLenToRead = 0U; 61 | } 62 | 63 | /* Interpret integer value of numeric representation. */ 64 | while( ( remainingLenToRead > 0U ) && ( *pLoc >= '0' ) && ( *pLoc <= '9' ) ) 65 | { 66 | result = ( result * 10 ) + ( int32_t ) ( *pLoc - '0' ); 67 | remainingLenToRead--; 68 | pLoc += 1; 69 | } 70 | 71 | if( remainingLenToRead != 0U ) 72 | { 73 | LogError( ( "Parsing Error: Expected numerical string of type '%%%d%c', " 74 | "but received '%.*s'.", 75 | ( int ) lenToRead, 76 | formatChar, 77 | ( int ) lenToRead, 78 | pLoc ) ); 79 | returnStatus = SigV4ISOFormattingError; 80 | } 81 | 82 | if( returnStatus != SigV4ISOFormattingError ) 83 | { 84 | addToDate( formatChar, 85 | result, 86 | pDateElements ); 87 | } 88 | 89 | return returnStatus; 90 | } 91 | 92 | void addToDate( const char formatChar, 93 | int32_t result, 94 | SigV4DateTime_t * pDateElements ) 95 | { 96 | assert( pDateElements != NULL ); 97 | assert( result >= 0 ); 98 | 99 | switch( formatChar ) 100 | { 101 | case 'Y': 102 | pDateElements->year = result; 103 | break; 104 | 105 | case 'M': 106 | pDateElements->mon = result; 107 | break; 108 | 109 | case 'D': 110 | pDateElements->mday = result; 111 | break; 112 | 113 | case 'h': 114 | pDateElements->hour = result; 115 | break; 116 | 117 | case 'm': 118 | pDateElements->min = result; 119 | break; 120 | 121 | case 's': 122 | pDateElements->sec = result; 123 | break; 124 | 125 | default: 126 | 127 | /* Do not assign values for skipped characters ('*'), or 128 | * unrecognized format specifiers. */ 129 | break; 130 | } 131 | } 132 | 133 | SigV4Status_t writeLineToCanonicalRequest( const char * pLine, 134 | size_t lineLen, 135 | CanonicalContext_t * pCanonicalContext ) 136 | { 137 | SigV4Status_t ret = SigV4InsufficientMemory; 138 | 139 | assert( pCanonicalContext != NULL ); 140 | 141 | if( pCanonicalContext->bufRemaining >= ( lineLen + 1U ) ) 142 | { 143 | assert( __CPROVER_w_ok( &( pCanonicalContext->pBufProcessing[ pCanonicalContext->uxCursorIndex ] ), ( lineLen + 1U ) ) ); 144 | ret = SigV4Success; 145 | } 146 | 147 | return ret; 148 | } 149 | 150 | SigV4Status_t SigV4_EncodeURI( const char * pUri, 151 | size_t uriLen, 152 | char * pCanonicalURI, 153 | size_t * canonicalURILen, 154 | bool encodeSlash, 155 | bool doubleEncodeEquals ) 156 | { 157 | SigV4Status_t returnStatus = SigV4Success; 158 | 159 | assert( pUri != NULL ); 160 | assert( pCanonicalURI != NULL ); 161 | assert( canonicalURILen != NULL ); 162 | 163 | if( nondet_bool() ) 164 | { 165 | returnStatus = SigV4Success; 166 | } 167 | else 168 | { 169 | returnStatus = SigV4InsufficientMemory; 170 | } 171 | 172 | return returnStatus; 173 | } 174 | 175 | SigV4Status_t generateCanonicalQuery( const char * pQuery, 176 | size_t queryLen, 177 | const bool doubleEncodeEqualsInParmsValues, 178 | CanonicalContext_t * pCanonicalContext ) 179 | { 180 | SigV4Status_t returnStatus = SigV4InsufficientMemory; 181 | 182 | assert( pCanonicalContext != NULL ); 183 | 184 | if( nondet_bool() ) 185 | { 186 | __CPROVER_assume( pCanonicalContext->bufRemaining < SIGV4_PROCESSING_BUFFER_LENGTH ); 187 | returnStatus = SigV4Success; 188 | } 189 | else 190 | { 191 | returnStatus = SigV4InsufficientMemory; 192 | } 193 | 194 | return returnStatus; 195 | } 196 | 197 | SigV4Status_t generateCanonicalAndSignedHeaders( const char * pHeaders, 198 | size_t headersLen, 199 | uint32_t flags, 200 | CanonicalContext_t * pCanonicalContext, 201 | char ** pSignedHeaders, 202 | size_t * pSignedHeadersLen ) 203 | { 204 | SigV4Status_t returnStatus = SigV4InsufficientMemory; 205 | 206 | assert( pHeaders != NULL ); 207 | assert( pCanonicalContext != NULL ); 208 | assert( pSignedHeaders != NULL ); 209 | assert( pSignedHeadersLen != NULL ); 210 | 211 | if( nondet_bool() ) 212 | { 213 | /* The signed headers are assumed to start at a location within the processing 214 | * buffer and should not end past the length of the processing buffer. */ 215 | size_t headersLen, headerOffset, bytesConsumed; 216 | char * pHeaders = NULL; 217 | __CPROVER_assume( pCanonicalContext->bufRemaining < SIGV4_PROCESSING_BUFFER_LENGTH ); 218 | bytesConsumed = SIGV4_PROCESSING_BUFFER_LENGTH - pCanonicalContext->bufRemaining; 219 | __CPROVER_assume( headerOffset < bytesConsumed ); 220 | __CPROVER_assume( headersLen > 0U && headersLen <= bytesConsumed - headerOffset ); 221 | pHeaders = ( char * ) pCanonicalContext->pBufProcessing + headerOffset; 222 | 223 | *pSignedHeadersLen = headersLen; 224 | *pSignedHeaders = pHeaders; 225 | returnStatus = SigV4Success; 226 | } 227 | else 228 | { 229 | returnStatus = SigV4InsufficientMemory; 230 | } 231 | 232 | return returnStatus; 233 | } 234 | 235 | SigV4Status_t copyHeaderStringToCanonicalBuffer( const char * pData, 236 | size_t dataLen, 237 | uint32_t flags, 238 | char separator, 239 | CanonicalContext_t * canonicalRequest ) 240 | { 241 | SigV4Status_t returnStatus = SigV4Success; 242 | size_t buffRemaining; 243 | 244 | __CPROVER_assume( pData != NULL ); 245 | __CPROVER_assume( dataLen > 0 ); 246 | __CPROVER_assume( dataLen < CBMC_MAX_OBJECT_SIZE ); 247 | 248 | assert( ( pData != NULL ) && ( dataLen > 0 ) ); 249 | assert( canonicalRequest != NULL ); 250 | 251 | buffRemaining = canonicalRequest->bufRemaining; 252 | 253 | if( buffRemaining < dataLen ) 254 | { 255 | returnStatus = SigV4InsufficientMemory; 256 | } 257 | 258 | return returnStatus; 259 | } 260 | -------------------------------------------------------------------------------- /test/include/sigv4_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_config.h 27 | * @brief Config values for testing the SigV4 for AWS IoT Library. 28 | */ 29 | 30 | #ifndef SIGV4_CONFIG_H_ 31 | #define SIGV4_CONFIG_H_ 32 | 33 | #include 34 | 35 | #ifdef DISABLE_LOGGING 36 | #ifndef LogError 37 | #define LogError( message ) 38 | #endif 39 | #ifndef LogWarn 40 | #define LogWarn( message ) 41 | #endif 42 | 43 | #ifndef LogInfo 44 | #define LogInfo( message ) 45 | #endif 46 | 47 | #ifndef LogDebug 48 | #define LogDebug( message ) 49 | #endif 50 | 51 | #else /* ! DISABLE_LOGGING */ 52 | #define LogError( message ) printf( "Error: " ); printf message; printf( "\n" ) 53 | 54 | #define LogWarn( message ) printf( "Warn: " ); printf message; printf( "\n" ) 55 | 56 | #define LogInfo( message ) printf( "Info: " ); printf message; printf( "\n" ) 57 | 58 | #define LogDebug( message ) printf( "Debug: " ); printf message; printf( "\n" ) 59 | #endif /* DISABLE_LOGGING */ 60 | 61 | #endif /* SIGV4_CONFIG_H_ */ 62 | -------------------------------------------------------------------------------- /test/unit-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Include filepaths for source and include. 2 | include( ${MODULE_ROOT_DIR}/sigv4FilePaths.cmake ) 3 | 4 | find_package(OpenSSL REQUIRED) 5 | 6 | # ==================== Define your project name (edit) ======================== 7 | set(project_name "sigv4") 8 | 9 | # ===================== Create your mock here (edit) ======================== 10 | # ================= Create the library under test here (edit) ================== 11 | 12 | # list the files you would like to test here 13 | list(APPEND real_source_files 14 | ${SIGV4_SOURCES} 15 | ) 16 | # list the directories the module under test includes 17 | list(APPEND real_include_directories 18 | . 19 | ${SIGV4_INCLUDE_PUBLIC_DIRS} 20 | "${CMAKE_CURRENT_LIST_DIR}/../include" 21 | ) 22 | 23 | # ===================== Create UnitTest Code here (edit) ===================== 24 | 25 | # list the directories your test needs to include 26 | list(APPEND test_include_directories 27 | . 28 | ${SIGV4_INCLUDE_PUBLIC_DIRS} 29 | ) 30 | 31 | # ============================= (end edit) =================================== 32 | 33 | set(real_name "${project_name}_real") 34 | 35 | create_real_library(${real_name} 36 | "${real_source_files}" 37 | "${real_include_directories}" 38 | "${mock_name}" 39 | ) 40 | 41 | list(APPEND utest_link_list 42 | lib${real_name}.a 43 | ) 44 | 45 | list(APPEND utest_dep_list 46 | ${real_name} 47 | ) 48 | 49 | set(utest_name "${project_name}_utest") 50 | set(utest_source "${project_name}_utest.c") 51 | create_test(${utest_name} 52 | ${utest_source} 53 | "${utest_link_list}" 54 | "${utest_dep_list}" 55 | "${test_include_directories}" 56 | ) 57 | 58 | target_link_libraries(${utest_name} OpenSSL::SSL) 59 | -------------------------------------------------------------------------------- /test/unit-test/cmock_build.cmake: -------------------------------------------------------------------------------- 1 | # Macro utility to clone the CMock submodule. 2 | macro( clone_cmock ) 3 | find_package( Git REQUIRED ) 4 | message( "Cloning submodule CMock." ) 5 | execute_process( COMMAND rm -rf ${CMOCK_DIR} 6 | COMMAND ${GIT_EXECUTABLE} submodule update --checkout --init --recursive ${CMOCK_DIR} 7 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} 8 | RESULT_VARIABLE CMOCK_CLONE_RESULT ) 9 | 10 | if( NOT ${CMOCK_CLONE_RESULT} STREQUAL "0" ) 11 | message( FATAL_ERROR "Failed to clone CMock submodule." ) 12 | endif() 13 | endmacro() 14 | 15 | # Macro utility to add library targets for Unity and CMock to build configuration. 16 | macro( add_cmock_targets ) 17 | # Build Configuration for CMock and Unity libraries. 18 | list( APPEND CMOCK_INCLUDE_DIRS 19 | "${CMOCK_DIR}/vendor/unity/src/" 20 | "${CMOCK_DIR}/vendor/unity/extras/fixture/src" 21 | "${CMOCK_DIR}/vendor/unity/extras/memory/src" 22 | "${CMOCK_DIR}/src" 23 | ) 24 | 25 | add_library(cmock STATIC 26 | "${CMOCK_DIR}/src/cmock.c" 27 | ) 28 | 29 | set_target_properties(cmock PROPERTIES 30 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 31 | POSITION_INDEPENDENT_CODE ON 32 | COMPILE_FLAGS "-Og" 33 | ) 34 | 35 | target_include_directories(cmock PUBLIC 36 | ${CMOCK_DIR}/src 37 | ${CMOCK_DIR}/vendor/unity/src/ 38 | ${CMOCK_DIR}/examples 39 | ${CMOCK_INCLUDE_DIRS} 40 | ) 41 | 42 | add_library(unity STATIC 43 | "${CMOCK_DIR}/vendor/unity/src/unity.c" 44 | "${CMOCK_DIR}/vendor/unity/extras/fixture/src/unity_fixture.c" 45 | "${CMOCK_DIR}/vendor/unity/extras/memory/src/unity_memory.c" 46 | ) 47 | 48 | set_target_properties(unity PROPERTIES 49 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 50 | POSITION_INDEPENDENT_CODE ON 51 | ) 52 | 53 | target_include_directories(unity PUBLIC 54 | ${CMOCK_INCLUDE_DIRS} 55 | ) 56 | 57 | target_link_libraries(cmock unity) 58 | endmacro() 59 | -------------------------------------------------------------------------------- /test/unit-test/sigv4_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SigV4 Library v1.3.0 3 | * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | * this software and associated documentation files (the "Software"), to deal in 9 | * the Software without restriction, including without limitation the rights to 10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | * the Software, and to permit persons to whom the Software is furnished to do so, 12 | * subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all 15 | * copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file sigv4_config.h 27 | * @brief The default values for configuration macros used by the SigV4 Library. 28 | * 29 | * @note This file should NOT be modified. If custom values are needed for any 30 | * configuration macros, a sigv4_config.h file should be provided to the SigV4 31 | * Library to override the default values defined in this file. To use 32 | * the custom config file, the preprocessor macro SIGV4_DO_NOT_USE_CUSTOM_CONFIG 33 | * must NOT be set. 34 | */ 35 | 36 | #ifndef SIGV4_CONFIG_H_ 37 | #define SIGV4_CONFIG_H_ 38 | 39 | /* @[code_example_loggingmacros] */ 40 | /************* Define Logging Macros using printf function ***********/ 41 | 42 | #define PrintfError( ... ) printf( "[%d] Error: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" ) 43 | #define PrintfWarn( ... ) printf( "[%d] Warn: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" ) 44 | #define PrintfInfo( ... ) printf( "[%d] Info: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" ) 45 | #define PrintfDebug( ... ) printf( "[%d] Debug: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" ) 46 | 47 | #ifdef LOGGING_LEVEL_ERROR 48 | #define LogError( message ) PrintfError message 49 | #elif defined( LOGGING_LEVEL_WARNING ) 50 | #define LogError( message ) PrintfError message 51 | #define LogWarn( message ) PrintfWarn message 52 | #elif defined( LOGGING_LEVEL_INFO ) 53 | #define LogError( message ) PrintfError message 54 | #define LogWarn( message ) PrintfWarn message 55 | #define LogInfo( message ) PrintfInfo message 56 | #elif defined( LOGGING_LEVEL_DEBUG ) 57 | #define LogError( message ) PrintfError message 58 | #define LogWarn( message ) PrintfWarn message 59 | #define LogInfo( message ) PrintfInfo message 60 | #define LogDebug( message ) PrintfDebug message 61 | #endif /* ifdef LOGGING_LEVEL_ERROR */ 62 | 63 | /**************************************************/ 64 | /* @[code_example_loggingmacros] */ 65 | 66 | /** 67 | * @brief Macro defining the size of the internal buffer used for incremental 68 | * canonicalization and hashing. 69 | * 70 | * A buffer of this size in bytes is declared on the stack. It should be be 71 | * large enough for the digest output of the specified hash function. 72 | * 73 | * Possible values: Any positive 32 bit integer.
74 | * Default value: `1024` 75 | */ 76 | #ifndef SIGV4_PROCESSING_BUFFER_LENGTH 77 | #define SIGV4_PROCESSING_BUFFER_LENGTH 428 78 | #endif 79 | 80 | /** 81 | * @brief Macro defining the maximum number of headers in the request, used to 82 | * assist the library in sorting header fields during canonicalization. 83 | * 84 | * This macro should be updated if the number of request headers the application 85 | * wishes to sign is higher or lower than the default value (100). 86 | * 87 | * Possible values: Any positive 32 bit integer.
88 | * Default value: `100` 89 | */ 90 | #ifndef SIGV4_MAX_HTTP_HEADER_COUNT 91 | #define SIGV4_MAX_HTTP_HEADER_COUNT 7U 92 | #endif 93 | 94 | /** 95 | * @brief Macro defining the maximum number of query key/value pairs, used to 96 | * assist the library in sorting query keys during canonicalization. 97 | * 98 | * This macro should be updated if the number of query key/value pairs the 99 | * application wishes to sign is higher or lower than the default value (100). 100 | * 101 | * Possible values: Any positive 32 bit integer.
102 | * Default value: `100` 103 | */ 104 | #ifndef SIGV4_MAX_QUERY_PAIR_COUNT 105 | #define SIGV4_MAX_QUERY_PAIR_COUNT 5U 106 | #endif 107 | 108 | #endif /* ifndef SIGV4_CONFIG_H_ */ 109 | -------------------------------------------------------------------------------- /tools/cmock/coverage.cmake: -------------------------------------------------------------------------------- 1 | # Taken from amazon-freertos repository 2 | cmake_minimum_required(VERSION 3.13) 3 | set(BINARY_DIR ${CMAKE_BINARY_DIR}) 4 | # reset coverage counters 5 | execute_process( 6 | COMMAND lcov --directory ${CMAKE_BINARY_DIR} 7 | --base-directory ${CMAKE_BINARY_DIR} 8 | --zerocounters 9 | 10 | COMMAND mkdir -p ${CMAKE_BINARY_DIR}/coverage 11 | ) 12 | # make the initial/baseline capture a zeroed out files 13 | execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR} 14 | --base-directory ${CMAKE_BINARY_DIR} 15 | --initial 16 | --capture 17 | --rc branch_coverage=1 18 | --ignore-errors empty 19 | --ignore-errors source 20 | --rc genhtml_branch_coverage=1 21 | --output-file=${CMAKE_BINARY_DIR}/base_coverage.info 22 | --quiet 23 | ) 24 | file(GLOB files "${CMAKE_BINARY_DIR}/bin/tests/*") 25 | 26 | set(REPORT_FILE ${CMAKE_BINARY_DIR}/utest_report.txt) 27 | file(WRITE ${REPORT_FILE} "") 28 | # execute all files in bin directory, gathering the output to show it in CI 29 | foreach(testname ${files}) 30 | get_filename_component(test 31 | ${testname} 32 | NAME_WLE 33 | ) 34 | message("Running ${testname}") 35 | execute_process(COMMAND ${testname} OUTPUT_FILE ${CMAKE_BINARY_DIR}/${test}_out.txt) 36 | 37 | file(READ ${CMAKE_BINARY_DIR}/${test}_out.txt CONTENTS) 38 | file(APPEND ${REPORT_FILE} "${CONTENTS}") 39 | endforeach() 40 | 41 | 42 | # generate Junit style xml output 43 | execute_process(COMMAND ruby 44 | ${CMOCK_DIR}/vendor/unity/auto/parse_output.rb 45 | -xml ${REPORT_FILE} 46 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 47 | ) 48 | 49 | # capture data after running the tests 50 | execute_process( 51 | COMMAND lcov --capture 52 | --rc branch_coverage=1 53 | --ignore-errors empty 54 | --ignore-errors source 55 | --rc genhtml_branch_coverage=1 56 | --base-directory ${CMAKE_BINARY_DIR} 57 | --directory ${CMAKE_BINARY_DIR} 58 | --output-file ${CMAKE_BINARY_DIR}/second_coverage.info 59 | --quiet 60 | ) 61 | 62 | # combile baseline results (zeros) with the one after running the tests 63 | execute_process( 64 | COMMAND lcov --base-directory ${CMAKE_BINARY_DIR} 65 | --directory ${CMAKE_BINARY_DIR} 66 | --add-tracefile ${CMAKE_BINARY_DIR}/base_coverage.info 67 | --add-tracefile ${CMAKE_BINARY_DIR}/second_coverage.info 68 | --output-file ${CMAKE_BINARY_DIR}/coverage.info 69 | --no-external 70 | --rc branch_coverage=1 71 | --ignore-errors empty 72 | --ignore-errors source 73 | --quiet 74 | ) 75 | execute_process( 76 | COMMAND genhtml --rc branch_coverage=1 77 | --ignore-errors empty 78 | --ignore-errors source 79 | --branch-coverage 80 | --output-directory ${CMAKE_BINARY_DIR}/coverage 81 | ${CMAKE_BINARY_DIR}/coverage.info 82 | --quiet 83 | ) 84 | -------------------------------------------------------------------------------- /tools/cmock/create_test.cmake: -------------------------------------------------------------------------------- 1 | # Taken from amazon-freertos repository 2 | 3 | #function to create the test executable 4 | function(create_test test_name 5 | test_src 6 | link_list 7 | dep_list 8 | include_list) 9 | set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks") 10 | include (CTest) 11 | get_filename_component(test_src_absolute ${test_src} ABSOLUTE) 12 | add_custom_command(OUTPUT ${test_name}_runner.c 13 | COMMAND ruby 14 | ${CMOCK_DIR}/vendor/unity/auto/generate_test_runner.rb 15 | ${MODULE_ROOT_DIR}/tools/cmock/project.yml 16 | ${test_src_absolute} 17 | ${test_name}_runner.c 18 | DEPENDS ${test_src} 19 | ) 20 | add_executable(${test_name} ${test_src} ${test_name}_runner.c) 21 | set_target_properties(${test_name} PROPERTIES 22 | COMPILE_FLAG "-O0 -ggdb" 23 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/tests" 24 | INSTALL_RPATH_USE_LINK_PATH TRUE 25 | LINK_FLAGS " \ 26 | -Wl,-rpath,${CMAKE_BINARY_DIR}/lib \ 27 | -Wl,-rpath,${CMAKE_CURRENT_BINARY_DIR}/lib" 28 | ) 29 | target_include_directories(${test_name} PUBLIC 30 | ${mocks_dir} 31 | ${include_list} 32 | ) 33 | 34 | target_link_directories(${test_name} PUBLIC 35 | ${CMAKE_CURRENT_BINARY_DIR} 36 | ) 37 | 38 | # link all libraries sent through parameters 39 | foreach(link IN LISTS link_list) 40 | target_link_libraries(${test_name} ${link}) 41 | endforeach() 42 | 43 | # add dependency to all the dep_list parameter 44 | foreach(dependency IN LISTS dep_list) 45 | add_dependencies(${test_name} ${dependency}) 46 | target_link_libraries(${test_name} ${dependency}) 47 | endforeach() 48 | target_link_libraries(${test_name} -lgcov unity) 49 | target_link_directories(${test_name} PUBLIC 50 | ${CMAKE_CURRENT_BINARY_DIR}/lib 51 | ) 52 | add_test(NAME ${test_name} 53 | COMMAND ${CMAKE_BINARY_DIR}/bin/tests/${test_name} 54 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 55 | ) 56 | endfunction() 57 | 58 | # Run the C preprocessor on target files. 59 | # Takes a CMAKE list of arguments to pass to the C compiler 60 | function(preprocess_mock_list mock_name file_list compiler_args) 61 | set_property(GLOBAL PROPERTY ${mock_name}_processed TRUE) 62 | foreach (target_file IN LISTS file_list) 63 | # Has to be TARGET ALL so the file is pre-processed before CMOCK 64 | # is executed on the file. 65 | add_custom_command(OUTPUT ${target_file}.backup 66 | COMMAND scp ${target_file} ${target_file}.backup 67 | VERBATIM COMMAND ${CMAKE_C_COMPILER} -E ${compiler_args} ${target_file} > ${target_file}.out 68 | ) 69 | add_custom_target(pre_${mock_name} 70 | COMMAND mv ${target_file}.out ${target_file} 71 | DEPENDS ${target_file}.backup 72 | ) 73 | endforeach() 74 | 75 | # Clean up temporary files that were created. 76 | # First we test to see if the backup file still exists. If it does we revert 77 | # the change made to the original file. 78 | foreach (target_file IN LISTS file_list) 79 | add_custom_command(TARGET ${mock_name} 80 | POST_BUILD 81 | COMMAND test ! -e ${target_file}.backup || mv ${target_file}.backup ${target_file} 82 | ) 83 | endforeach() 84 | endfunction() 85 | 86 | # Generates a mock library based on a module's header file 87 | # places the generated source file in the build directory 88 | # @param mock_name: name of the target name 89 | # @param mock_list list of header files to mock 90 | # @param cmock_config configuration file of the cmock framework 91 | # @param mock_include_list include list for the target 92 | # @param mock_define_list special definitions to control compilation 93 | function(create_mock_list mock_name 94 | mock_list 95 | cmock_config 96 | mock_include_list 97 | mock_define_list) 98 | set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks") 99 | add_library(${mock_name} SHARED) 100 | foreach (mock_file IN LISTS mock_list) 101 | get_filename_component(mock_file_abs 102 | ${mock_file} 103 | ABSOLUTE 104 | ) 105 | get_filename_component(mock_file_name 106 | ${mock_file} 107 | NAME_WLE 108 | ) 109 | get_filename_component(mock_file_dir 110 | ${mock_file} 111 | DIRECTORY 112 | ) 113 | add_custom_command ( 114 | OUTPUT ${mocks_dir}/mock_${mock_file_name}.c 115 | COMMAND ruby 116 | ${CMOCK_DIR}/lib/cmock.rb 117 | -o${cmock_config} ${mock_file_abs} 118 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 119 | ) 120 | target_sources(${mock_name} PUBLIC 121 | ${mocks_dir}/mock_${mock_file_name}.c 122 | ) 123 | 124 | target_include_directories(${mock_name} PUBLIC 125 | ${mock_file_dir} 126 | ) 127 | endforeach() 128 | target_include_directories(${mock_name} PUBLIC 129 | ${mocks_dir} 130 | ${mock_include_list} 131 | ) 132 | set_target_properties(${mock_name} PROPERTIES 133 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib 134 | POSITION_INDEPENDENT_CODE ON 135 | ) 136 | target_compile_definitions(${mock_name} PUBLIC 137 | ${mock_define_list} 138 | ) 139 | target_link_libraries(${mock_name} cmock unity) 140 | endfunction() 141 | 142 | 143 | function(create_real_library target 144 | src_file 145 | real_include_list 146 | mock_name) 147 | add_library(${target} STATIC 148 | ${src_file} 149 | ) 150 | target_include_directories(${target} PUBLIC 151 | ${real_include_list} 152 | ) 153 | set_target_properties(${target} PROPERTIES 154 | COMPILE_FLAGS "-Wextra -Wpedantic \ 155 | -fprofile-arcs -ftest-coverage -fprofile-generate \ 156 | -Wno-unused-but-set-variable" 157 | LINK_FLAGS "-fprofile-arcs -ftest-coverage \ 158 | -fprofile-generate " 159 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib 160 | ) 161 | if(NOT(mock_name STREQUAL "")) 162 | add_dependencies(${target} ${mock_name}) 163 | target_link_libraries(${target} 164 | -l${mock_name} 165 | -lgcov 166 | ) 167 | endif() 168 | endfunction() 169 | -------------------------------------------------------------------------------- /tools/cmock/project.yml: -------------------------------------------------------------------------------- 1 | # Taken from amazon-freertos repository 2 | :cmock: 3 | :mock_prefix: mock_ 4 | :when_no_prototypes: :warn 5 | :enforce_strict_ordering: TRUE 6 | :plugins: 7 | - :ignore 8 | - :ignore_arg 9 | - :expect_any_args 10 | - :array 11 | - :callback 12 | - :return_thru_ptr 13 | :callback_include_count: true # include a count arg when calling the callback 14 | :callback_after_arg_check: false # check arguments before calling the callback 15 | :treat_as: 16 | uint8: HEX8 17 | uint16: HEX16 18 | uint32: UINT32 19 | int8: INT8 20 | bool: UINT8 21 | :includes: # This will add these includes to each mock. 22 | - 23 | - 24 | :treat_externs: :exclude # Now the extern-ed functions will be mocked. 25 | :weak: __attribute__((weak)) 26 | :treat_externs: :include 27 | -------------------------------------------------------------------------------- /tools/coverity/README.md: -------------------------------------------------------------------------------- 1 | # Static code analysis for AWS SigV4 Library 2 | This directory is made for the purpose of statically testing the MISRA C:2012 compliance of AWS SigV4 Library using 3 | [Synopsys Coverity](https://www.synopsys.com/software-integrity/security-testing/static-analysis-sast.html) static analysis tool. 4 | To that end, this directory provides a [configuration file](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/blob/main/tools/coverity/misra.config) to use when 5 | building a binary for the tool to analyze. 6 | 7 | > **Note** 8 | For generating the report as outlined below, we have used Coverity version 2023.6.1. 9 | 10 | For details regarding the suppressed violations in the report (which can be generated using the instructions described below), please 11 | see the [MISRA.md](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/blob/main/MISRA.md) file. 12 | 13 | ## Getting Started 14 | ### Prerequisites 15 | You can run this on a platform supported by Coverity. The list and other details can be found [here](https://sig-docs.synopsys.com/polaris/topics/c_coverity-compatible-platforms.html). 16 | To compile and run the Coverity target successfully, you must have the following: 17 | 18 | 1. CMake version > 3.13.0 (You can check whether you have this by typing `cmake --version`) 19 | 2. GCC compiler 20 | - You can see the downloading and installation instructions [here](https://gcc.gnu.org/install/). 21 | 3. Download the repo and include the submodules using the following commands. 22 | - `git clone --recurse-submodules git@github.com:aws/SigV4-for-AWS-IoT-embedded-sdk.git ./SigV4-for-AWS-IoT-embedded-sdk` 23 | - `cd ./SigV4-for-AWS-IoT-embedded-sdk` 24 | - `git submodule update --checkout --init --recursive` 25 | 26 | ### To build and run coverity: 27 | Go to the root directory of the library and run the following commands in terminal: 28 | 1. Update the compiler configuration in Coverity 29 | ~~~ 30 | cov-configure --force --compiler cc --comptype gcc 31 | ~~~ 32 | 2. Create the build files using CMake in a `build` directory 33 | ~~~ 34 | cmake -B build -S test 35 | ~~~ 36 | 3. Go to the build directory and copy the coverity configuration file 37 | ~~~ 38 | cd build/ 39 | ~~~ 40 | 4. Build the static analysis target 41 | ~~~ 42 | cov-build --emit-complementary-info --dir cov-out make coverity_analysis 43 | ~~~ 44 | 5. Go to the Coverity output directory (`cov-out`) and begin Coverity static analysis 45 | ~~~ 46 | cd cov-out/ 47 | cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')" 48 | ~~~ 49 | 6. Format the errors in HTML format so that it is more readable while removing the test and build directory from the report 50 | ~~~ 51 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out; 52 | ~~~ 53 | 7. Format the errors in JSON format to perform a jq query to get a simplified list of any exceptions. 54 | NOTE: A blank output means there are no defects that aren't being suppressed by the config or inline comments. 55 | ~~~ 56 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json; 57 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n"; 58 | jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr; 59 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n"; 60 | ~~~ 61 | 62 | For your convenience the commands above are below to be copy/pasted into a UNIX command friendly terminal. 63 | ~~~ 64 | cov-configure --force --compiler cc --comptype gcc; 65 | cmake -B build -S test; 66 | cd build/; 67 | cov-build --emit-complementary-info --dir cov-out make coverity_analysis; 68 | cd cov-out/ 69 | cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')"; 70 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out; 71 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json; 72 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n"; 73 | jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr; 74 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n"; 75 | cd ../../; 76 | ~~~ 77 | 78 | You should now have the HTML formatted violations list in a directory named `build/cov-out/html-output`. 79 | With the current configuration and the provided project, you should not see any deviations. 80 | -------------------------------------------------------------------------------- /tools/coverity/misra.config: -------------------------------------------------------------------------------- 1 | { 2 | "version" : "2.0", 3 | "standard" : "c2012", 4 | "title" : "Coverity MISRA Configuration", 5 | "deviations" : [ 6 | { 7 | "deviation" : "Directive 4.9", 8 | "reason" : "Allow inclusion of function like macros. Asserts and logging use function like macros." 9 | }, 10 | { 11 | "deviation" : "Rule 2.4", 12 | "reason" : "Allow unused tags. Some compilers warn if types are not tagged." 13 | }, 14 | { 15 | "deviation" : "Rule 2.5", 16 | "reason" : "Allow unused macros." 17 | }, 18 | { 19 | "deviation" : "Rule 3.1", 20 | "reason" : "Allow nested comments. C++ style `//` comments are used in example code within Doxygen documentation blocks." 21 | }, 22 | { 23 | "deviation" : "Rule 8.7", 24 | "reason" : "API functions are not used by the library outside of the files they are defined in; however, they must be externally visible in order to be used by an application." 25 | }, 26 | { 27 | "deviation" : "Rule 11.5", 28 | "reason" : "Allow casts from void *. Functions with void * parameters are used while sorting." 29 | } 30 | ] 31 | } 32 | --------------------------------------------------------------------------------