[修改] 增加freeRTOS

1. 版本FreeRTOSv202212.01,命名为kernel;
This commit is contained in:
2023-05-06 16:43:01 +00:00
commit a345df017b
20944 changed files with 11094377 additions and 0 deletions

View File

@ -0,0 +1,63 @@
# Contributing Guidelines
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
documentation, we greatly value feedback and contributions from our community.
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
information to effectively respond to your bug report or contribution.
## Reporting Bugs/Feature Requests
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
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
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
* A reproducible test case or series of steps
* The version of our code being used
* Any modifications you've made relevant to the bug
* Anything unusual about your environment or deployment
## Contributing via Pull Requests
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
1. You are working against the latest source on the *main* branch.
1. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
1. You open an issue to discuss any significant work - we would hate for your time to be wasted.
To send us a pull request, please:
1. Fork the repository.
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.
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).
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).
1. Ensure local tests pass.
1. Commit to your fork using clear commit messages.
1. Send us a pull request, answering any default questions in the pull request interface.
1. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
## Finding contributions to work on
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.
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.
## Security issue notifications
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.
## Licensing
See the [LICENSE](../LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
We may ask you to sign a [Contributor License Agreement (CLA)](https://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.

View File

@ -0,0 +1 @@
https://www.somewebsite.com/path/to/item.txt?optionalquery=stuff

View File

@ -0,0 +1,13 @@
{
"lib_name": "AWS SigV4 library",
"src": [
"source/sigv4.c",
"source/sigv4_quicksort.c"
],
"include": [
"source/include"
],
"compiler_flags": [
"SIGV4_DO_NOT_USE_CUSTOM_CONFIG"
]
}

View File

@ -0,0 +1,6 @@
*Issue #, if available:*
*Description of changes:*
By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

View File

@ -0,0 +1,146 @@
name: CI Checks
on:
push:
branches: ["**"]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
build-check-library:
runs-on: ubuntu-latest
steps:
- name: Clone This Repo
uses: actions/checkout@v2
- name: Build in Release Mode
run: |
cmake -S test -B build/ \
-G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_FLAGS='-Wall -Wextra -Werror'
make -C build/ all
unittest:
runs-on: ubuntu-latest
steps:
- name: Clone This Repo
uses: actions/checkout@v2
- name: Build
run: |
sudo apt-get install -y lcov
cmake -S test -B build/ \
-G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_UNIT_TESTS=ON \
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -DNDEBUG -DLOGGING_LEVEL_DEBUG=1'
make -C build/ all
- name: Test
run: |
cd build/
ctest -E system --output-on-failure
cd ..
- name: Run Coverage
run: |
make -C build/ coverage
declare -a EXCLUDE=("\*test\*" "\*CMakeCCompilerId\*" "\*mocks\*")
echo ${EXCLUDE[@]} | xargs lcov --rc lcov_branch_coverage=1 -r build/coverage.info -o build/coverage.info
lcov --rc lcov_branch_coverage=1 --list build/coverage.info
- name: Check Coverage
uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
with:
path: ./build/coverage.info
build-with-default-config:
runs-on: ubuntu-latest
steps:
- name: Clone This Repo
uses: actions/checkout@v2
- name: Build
run: |
cmake -S test -B build/ \
-G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_FLAGS='-Wall -Wextra -Werror -DSIGV4_DO_NOT_USE_CUSTOM_CONFIG'
make -C build/ all
complexity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Check complexity
uses: FreeRTOS/CI-CD-Github-Actions/complexity@main
with:
path: ./
doxygen:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Run doxygen build
uses: FreeRTOS/CI-CD-Github-Actions/doxygen@main
with:
path: ./
spell-check:
runs-on: ubuntu-latest
steps:
- name: Clone This Repo
uses: actions/checkout@v2
- name: Run spellings check
uses: FreeRTOS/CI-CD-Github-Actions/spellings@main
with:
path: ./
formatting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Check formatting
uses: FreeRTOS/CI-CD-Github-Actions/formatting@main
with:
path: ./
git-secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Checkout awslabs/git-secrets
uses: actions/checkout@v2
with:
repository: awslabs/git-secrets
ref: master
path: git-secrets
- name: Install git-secrets
run: cd git-secrets && sudo make install && cd ..
- name: Run git-secrets
run: |
git-secrets --register-aws
git-secrets --scan
memory_statistics:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Install Python3
uses: actions/setup-python@v2
with:
python-version: '3.7.10'
- name: Measure sizes
uses: FreeRTOS/CI-CD-Github-Actions/memory_statistics@main
with:
config: .github/memory_statistics_config.json
check_against: docs/doxygen/include/size_table.md
link-verifier:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Setup Python for link verifier action
uses: actions/setup-python@v2
with:
python-version: '3.7.10'
- name: Check Links
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: FreeRTOS/CI-CD-GitHub-Actions/link-verifier@main
with:
path: ./
exclude-dirs: cmock,unity,cbmc
include-file-types: .c,.h,.dox
allowlist-file: ./.github/links_allowlist.txt

View File

@ -0,0 +1,11 @@
name: Doxygen Generation
on:
push:
branches: [main]
workflow_dispatch:
jobs:
doxygen-generation:
runs-on: ubuntu-latest
steps:
- name: Doxygen generation
uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main

View File

@ -0,0 +1,139 @@
name: Release automation
on:
workflow_dispatch:
inputs:
commit_id:
description: 'Commit ID to tag and create a release for'
required: true
version_number:
description: 'Release Version Number (Eg, v1.0.0)'
required: true
jobs:
tag-commit:
name: Generate SBOM and tag commit
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.commit_id }}
- name: Configure git identity
run: |
git config --global user.name ${{ github.actor }}
git config --global user.email ${{ github.actor }}@users.noreply.github.com
- name: create a new branch that references commit id
run: git checkout -b ${{ github.event.inputs.version_number }} ${{ github.event.inputs.commit_id }}
- name: Generate SBOM
uses: FreeRTOS/CI-CD-Github-Actions/sbom-generator@main
with:
repo_path: ./
source_path: ./source
- name: commit SBOM file
run: |
git add .
git commit -m 'Update SBOM'
git push -u origin ${{ github.event.inputs.version_number }}
- name: Tag Commit and Push to remote
run: |
git tag ${{ github.event.inputs.version_number }} -a -m "AWS IoT SigV4 ${{ github.event.inputs.version_number }}"
git push origin --tags
- name: Verify tag on remote
run: |
git tag -d ${{ github.event.inputs.version_number }}
git remote update
git checkout tags/${{ github.event.inputs.version_number }}
git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }}
create-zip:
needs: tag-commit
name: Create ZIP and verify package for release asset.
runs-on: ubuntu-latest
steps:
- name: Install ZIP tools
run: sudo apt-get install zip unzip
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.commit_id }}
path: SigV4-for-AWS-IoT-embedded-sdk
submodules: recursive
- name: Checkout disabled submodules
run: |
cd SigV4-for-AWS-IoT-embedded-sdk
git submodule update --init --checkout --recursive
- name: Create ZIP
run: |
zip -r SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip SigV4-for-AWS-IoT-embedded-sdk -x "*.git*"
ls ./
- name: Validate created ZIP
run: |
mkdir zip-check
mv SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip zip-check
cd zip-check
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 }}
ls SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}
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/
cd ../
- name: Build
run: |
cd zip-check/SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/SigV4-for-AWS-IoT-embedded-sdk
sudo apt-get install -y lcov
cmake -S test -B build/ \
-G "Unix Makefiles" \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_CLONE_SUBMODULES=ON \
-DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG'
make -C build/ all
- name: Test
run: |
cd zip-check/SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/SigV4-for-AWS-IoT-embedded-sdk/build/
ctest -E system --output-on-failure
cd ..
- name: Create artifact of ZIP
uses: actions/upload-artifact@v2
with:
name: SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
path: zip-check/SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
deploy-doxygen:
needs: tag-commit
name: Deploy doxygen documentation
runs-on: ubuntu-latest
steps:
- name: Doxygen generation
uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main
with:
ref: ${{ github.event.inputs.version_number }}
add_release: "true"
create-release:
needs:
- create-zip
- deploy-doxygen
name: Create Release and Upload Release Asset
runs-on: ubuntu-latest
steps:
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.event.inputs.version_number }}
release_name: ${{ github.event.inputs.version_number }}
body: Release ${{ github.event.inputs.version_number }} of AWS IoT SigV4.
draft: false
prerelease: false
- name: Download ZIP artifact
uses: actions/download-artifact@v2
with:
name: SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
asset_name: SigV4-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
asset_content_type: application/zip

View File

@ -0,0 +1,13 @@
# Ignore documentation output.
**/docs/**/output/*
# Ignore CMake build directory.
build/
# Ignore build artifacts.
*.o
# Ignore code coverage artifacts.
*.gcda
*.gcno
*.gcov

View File

@ -0,0 +1,4 @@
[submodule "test/unit-test/CMock"]
path = test/unit-test/CMock
url = https://github.com/ThrowTheSwitch/CMock.git
update = none

View File

@ -0,0 +1,22 @@
# Changelog for AWS SigV4 Library
## v1.2.0 (October 2022)
- [#71](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/71) MISRA C:2012 Compliance Update
- [#70](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/70) Update CBMC starter kit
## v1.1.0 (December 2021)
- [#63](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/63) Remove extraneous parentheses in isAllowedChar()
- [#62](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/62) Enable logging macros in CI checks for SigV4
- [#59](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/59) Remove superfluous memmove
- [#58](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/58) Utility word removal from Sigv4 Library
- [#57](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/57) SigV4 Porting Guide
- [#56](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/56) Update Doxygen version to 1.9.2
- [#55](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/55) CBMC Proof Failure Fixes
- [#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.
- [#51](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/pull/51) Payload hash optimization
## v1.0.0 (August 2021)
This is the first release of the AWS SigV4 Library.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,23 @@
# MISRA Compliance
The AWS SigV4 Library files conform to the [MISRA C:2012](https://www.misra.org.uk)
guidelines, with some noted exceptions. Compliance is checked with Coverity static analysis.
The specific deviations, suppressed inline, are listed below.
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.
### Suppressed with Coverity Comments
To find the deviation references in the source files run grep on the source code
with ( Assuming rule 5.4 violation; with justification in point 1 ):
```
grep 'MISRA Ref 5.4.1' . -rI
```
#### Rule 5.4
_Ref 5.4.1_
- MISRA Rule 5.4 flags the following macro's name as ambiguous from the
one postfixed with _LENGTH. The macro highlighted by the deviation is already
in use and changing the name will break existing user projects. Thus, for
backwards compatibility, the macro is not modified and kept as is and the
deviation is suppressed.

View File

@ -0,0 +1,93 @@
# AWS SigV4 Library
The AWS SigV4 Library is a standalone library for generating authorization headers and signatures according to the specifications of the [Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) signing process. Authorization headers are required for authentication when sending HTTP requests to AWS. This library can optionally be used by applications sending direct HTTP requests to AWS services requiring SigV4 authentication. This library has no dependencies on any additional libraries other than the standard C library. This library is distributed under the MIT Open Source License.
This library has gone through code quality checks including verification that no function has a GNU Complexity score over 8, and checks against deviations from mandatory rules in the MISRA coding standard. Deviations from the MISRA C:2012 guidelines are documented under MISRA Deviations. This library has also undergone static code analysis using Coverity static analysis, and validation of memory safety through the CBMC automated reasoning tool.
See memory requirements for this library [here][memory_table].
[memory_table]: ./docs/doxygen/include/size_table.md
**AWS SigV4 v1.2.0 [source code](https://github.com/aws/Sigv4-for-AWS-IoT-embedded-sdk/tree/v1.2.0/source) is part of the [FreeRTOS 202210.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202210.00-LTS) release.**
## AWS SigV4 Library Config File
The AWS SigV4 library exposes build configuration
macros that are required for building the library. A list of all the
configurations and their default values are defined in
[sigv4_config_defaults.h][default_config]. To provide custom values for the
configuration macros, a config file named `sigv4_config.h` can be
provided by the application to the library.
[default_config]: source/include/sigv4_config_defaults.h
By default, a `sigv4_config.h` config file is required to build
the library. To disable this requirement and build the library with default
configuration values, provide `SIGV4_DO_NOT_USE_CUSTOM_CONFIG` as
a compile time preprocessor macro.
**Thus, the SigV4 library can be built by either**:
* Defining a `sigv4_config.h` file in the application, and adding
it to the include directories list of the library.
**OR**
* Defining the `SIGV4_DO_NOT_USE_CUSTOM_CONFIG` preprocessor macro
for the library build.
## Building the SigV4 Library
The [sigv4FilePaths.cmake](sigv4FilePaths.cmake) file contains information of all the source files and header include paths required to build the SigV4 library.
As mentioned in the previous section, either a custom config file (i.e.
`sigv4_config.h`) or `SIGV4_DO_NOT_USE_CUSTOM_CONFIG`
macro needs to be provided to build the SigV4 library.
To use CMake, please refer to the [sigV4FilePaths.cmake](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/blob/main/sigv4FilePaths.cmake) file, which contains the relevant information regarding source files and header include paths required to build this library.
## Building Unit Tests
### Platform Prerequisites
- For running unit tests:
- **C90 compiler** like gcc.
- **CMake 3.13.0 or later**.
- **Ruby 2.0.0 or later** is additionally required for the CMock test framework (that we use).
- For running the coverage target, **gcov** and **lcov** are additionally required.
### Steps to build **Unit Tests**
1. Go to the root directory of this repository.
1. Run the *cmake* command: `cmake -S test -B build -DBUILD_UNIT_TESTS=ON`.
1. Run this command to build the library and unit tests: `make -C build all`.
1. The generated test executables will be present in `build/bin/tests` folder.
1. Run `cd build && ctest` to execute all tests and view the test run summary.
## CBMC
To learn more about CBMC and proofs specifically, review the training material [here](https://model-checking.github.io/cbmc-training).
The `test/cbmc/proofs` directory contains CBMC proofs.
In order to run these proofs you will need to install CBMC and other tools by following the instructions [here](https://model-checking.github.io/cbmc-training/installation.html).
## Reference examples
The AWS IoT Embedded C-SDK repository contains [HTTP demos](https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/main/demos/http) showing the use of the AWS SigV4 Library on a POSIX platform to authenticate HTTP requests to AWS S3 service.
## Generating documentation
The Doxygen references found in this repository were created using Doxygen
version 1.9.2. To generate these Doxygen pages, please run the following
command from the root of this repository:
```shell
doxygen docs/doxygen/config.doxyfile
```
## Contributing
See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for information on contributing.

View File

@ -0,0 +1,5 @@
## Reporting a Vulnerability
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/) or directly via email to aws-security@amazon.com.
Please do **not** create a public github issue.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
<table>
<tr>
<td colspan="3"><center><b>Code Size of AWS SigV4 library (example generated with GCC for ARM Cortex-M)</b></center></td>
</tr>
<tr>
<td><b>File</b></td>
<td><b><center>With -O1 Optimization</center></b></td>
<td><b><center>With -Os Optimization</center></b></td>
</tr>
<tr>
<td>sigv4.c</td>
<td><center>5.2K</center></td>
<td><center>4.4K</center></td>
</tr>
<tr>
<td>sigv4_quicksort.c</td>
<td><center>0.4K</center></td>
<td><center>0.3K</center></td>
</tr>
<tr>
<td><b>Total estimates</b></td>
<td><b><center>5.6K</center></b></td>
<td><b><center>4.7K</center></b></td>
</tr>
</table>

View File

@ -0,0 +1,233 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.8.20 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<!-- Hide the default "Data Structures" tab and use the "Modules" tab for data
structures. This allows internal data structures to be hidden. -->
<tab type="modules" visible="yes" title="Data types and Constants" intro="This library defines the following data types and constants."/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="interfaces" visible="no" title="">
<tab type="interfacelist" visible="no" title="" intro=""/>
<tab type="interfaceindex" visible="no" title=""/>
<tab type="interfacehierarchy" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="no" title="">
<tab type="classlist" visible="no" title="" intro=""/>
<tab type="classindex" visible="no" title=""/>
<tab type="hierarchy" visible="no" title="" intro=""/>
<tab type="classmembers" visible="no" title="" intro=""/>
</tab>
<tab type="structs" visible="no" title="">
<tab type="structlist" visible="no" title="" intro=""/>
<tab type="structindex" visible="no" title=""/>
</tab>
<tab type="exceptions" visible="no" title="">
<tab type="exceptionlist" visible="no" title="" intro=""/>
<tab type="exceptionindex" visible="no" title=""/>
<tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="no" title="">
<tab type="filelist" visible="yes" title="Files" intro="The following files are associated with this library."/>
<tab type="globals" visible="no" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

View File

@ -0,0 +1,92 @@
/**
@mainpage Overview
@anchor sigv4
@brief AWS SigV4 Library
The AWS SigV4 Library is a standalone library for generating signatures
and authorization headers according to the specifications of the AWS Signature
Version 4 signing process. This library aids applications in sending direct
HTTP requests to AWS services requiring SigV4 authentication. The library is
written in C and designed to be compliant with ISO C90 and MISRA C and has no
dependencies on any additional libraries other than the standard C library.
@section sigv4_memory_requirements Memory Requirements
@brief Memory requirements of the SigV4 Library.
@include{doc} size_table.md
@section sigv4_design Design
@brief SigV4 Library Design
<h3>Memory Usage</h3>
<p>
All functions in the SigV4 library operate only on the buffers provided and use only
local variables on the stack.
</p>
<h3>Compliance & Coverage</h3>
<p>
The SIGV4 library is designed to be compliant with ISO C90 and MISRA C:2012.
All functions are written to have low complexity scores. Unit tests and CBMC
proofs are written to cover every path of execution and achieve 100% branch
coverage.
</p>
The diagram below demonstrates the happy path an application can take to use
the SigV4 library to interact with AWS Services that support SigV4 authentication via HTTP requests.
@image html sigv4_design.png "SigV4 Library Usage diagram" width=90%
*/
/**
@page sigv4_config Configurations
@brief Configurations of the AWS SigV4 Library.
<!-- @par configpagestyle allows the @section titles to be styled according to
style.css -->
@par configpagestyle
Configuration settings are C pre-processor constants. They can be set with a
`\#define` in the config file (`sigv4_config.h`) or by using a
compiler option such as -D in gcc.
@section SIGV4_DO_NOT_USE_CUSTOM_CONFIG
@copydoc SIGV4_DO_NOT_USE_CUSTOM_CONFIG
@section sigv4_logerror LogError
@copydoc LogError
@section sigv4_logwarn LogWarn
@copydoc LogWarn
@section sigv4_loginfo LogInfo
@copydoc LogInfo
@section sigv4_logdebug LogDebug
@copydoc LogDebug
*/
/**
@page sigv4_functions Functions
@brief Primary functions of the AWS SigV4 library:<br><br>
@subpage sigV4_generateHTTPAuthorization_function <br>
@subpage sigV4_awsIotDateToIso8601_function <br>
@page sigV4_generateHTTPAuthorization_function SigV4_GenerateHTTPAuthorization
@snippet sigv4.h declare_sigV4_generateHTTPAuthorization_function
@copydoc SigV4_GenerateHTTPAuthorization
@page sigV4_awsIotDateToIso8601_function SigV4_AwsIotDateToIso8601
@snippet sigv4.h declare_sigV4_awsIotDateToIso8601_function
@copydoc SigV4_AwsIotDateToIso8601
*/
<!-- We do not use doxygen ALIASes here because there have been issues in the past versions with "^^" newlines within the alias definition. -->
/**
@defgroup sigv4_enum_types Enumerated Types
@brief Enumerated types of the SigV4 library
@defgroup sigv4_struct_types Struct Types
@brief Struct types of the SigV4 library
*/

View File

@ -0,0 +1,72 @@
/**
* @page sigv4_porting Porting Guide
* @brief Guide for porting the AWS SigV4 Library to a new
* platform.
*
* To use the AWS SigV4 library, a platform must implement the following
* components:
* 1. [Configuration Macros](@ref sigv4_config_macros)
* 2. [Crypto Interface](@ref sigv4_porting_cryptointerface)
*
* @section sigv4_config_macros Configuration Macros
* @brief Configuration macros that can be set in the config header
* `sigv4_config.h`, or passed in as compiler options.
*
* The following optional logging macros are used throughout the library:
* - @ref LogError
* - @ref LogWarn
* - @ref LogInfo
* - @ref LogDebug
*
* @see [Configurations](@ref sigv4_config) for more information.
*
* @note Regardless of whether the above macros are defined in
* `sigv4_config.h` or passed as compiler options, by default the
* `sigv4_config.h` file is needed to build the AWS SigV4 Library. To disable this requirement and build the library with
* default configuration values, provide
* `SIGV4_DO_NOT_USE_CUSTOM_CONFIG` as a compile time preprocessor
* macro.
*
* @section sigv4_porting_cryptointerface Crypto Interface
* @brief The AWS SigV4 library relies on the implementation of crypto interface
* to provide hash functions used in generating the Authorization header by the library.
*
* A port must implement functions corresponding to the
* following functions pointers:
* - [Hash Initialize]: A function to initialize the Hash Context.
* @code
* int32_t ( * hashInit )( void * pHashContext );
* @endcode
* - [Hash Update]: A function to update the hash to be calculated with more input data.
* @code
* int32_t ( * hashUpdate )( void * pHashContext,
* const uint8_t * pInput,
* size_t inputLen );
* @endcode
* - [Hash Final]: A function to calculate the final binary digest of the hash from the context.
* @code
* int32_t ( * hashFinal )( void * pHashContext,
* uint8_t * pOutput,
* size_t outputLen );
* @endcode
*
* The above three functions take in a pointer to pHashContext which defines the context used
* by the above function in calculating the hash. The HashContext must also be
* defined by the user's implementation and ought to contain any information
* necessary to calculate the hash.
* @code
* void * pHashContext;
* @endcode
*
* A port must also define the following:
* - [Hash Block Length]: The block length of the hash function implemented by the user.
* @code
* size_t hashBlockLen;
* @endcode
*
* - [Hash Digest Length]: The digest length of the hash function implemented by the user.
* @code
* size_t hashDigestLen;
* @endcode
*
*/

View File

@ -0,0 +1,152 @@
/*
* Stylesheet for Doxygen HTML output.
*
* This file defines styles for custom elements in the header/footer and
* overrides some of the default Doxygen styles.
*
* Styles in this file do not affect the treeview sidebar.
*/
/* Set the margins to place a small amount of whitespace on the left and right
* side of the page. */
div.contents {
margin-left:4em;
margin-right:4em;
}
/* Justify text in paragraphs. */
p {
text-align: justify;
}
/* Style of section headings. */
h1 {
border-bottom: 1px solid #879ECB;
color: #354C7B;
font-size: 160%;
font-weight: normal;
padding-bottom: 4px;
padding-top: 8px;
}
/* Style of subsection headings. */
h2:not(.memtitle):not(.groupheader) {
font-size: 125%;
margin-bottom: 0px;
margin-top: 16px;
padding: 0px;
}
/* Style of paragraphs immediately after subsection headings. */
h2 + p {
margin: 0px;
padding: 0px;
}
/* Style of subsection headings. */
h3 {
font-size: 100%;
margin-bottom: 0px;
margin-left: 2em;
margin-right: 2em;
}
/* Style of paragraphs immediately after subsubsection headings. */
h3 + p {
margin-top: 0px;
margin-left: 2em;
margin-right: 2em;
}
/* Style of the prefix "AWS IoT Device SDK C" that appears in the header. */
#csdkprefix {
color: #757575;
}
/* Style of the "Return to main page" link that appears in the header. */
#returntomain {
padding: 0.5em;
}
/* Style of the dividers on Configuration Settings pages. */
div.configpagedivider {
margin-left: 0px !important;
margin-right: 0px !important;
margin-top: 20px !important;
}
/* Style of configuration setting names. */
dl.section.user ~ h1 {
border-bottom: none;
color: #000000;
font-family: monospace, fixed;
font-size: 16px;
margin-bottom: 0px;
margin-left: 2em;
margin-top: 1.5em;
}
/* Style of paragraphs on a configuration settings page. */
dl.section.user ~ * {
margin-bottom: 10px;
margin-left: 4em;
margin-right: 4em;
margin-top: 0px;
}
/* Hide the configuration setting marker. */
dl.section.user {
display: none;
}
/* Overrides for code fragments and lines. */
div.fragment {
background: #ffffff;
border: none;
padding: 5px;
}
div.line {
color: #3a3a3a;
}
/* Overrides for code syntax highlighting colors. */
span.comment {
color: #008000;
}
span.keyword, span.keywordtype, span.keywordflow {
color: #0000ff;
}
span.preprocessor {
color: #50015a;
}
span.stringliteral, span.charliteral {
color: #800c0c;
}
a.code, a.code:visited, a.line, a.line:visited {
color: #496194;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

View File

@ -0,0 +1,53 @@
@startuml
skinparam dpi 100
skinparam classFontSize 8
skinparam classFontName Helvetica
autonumber
box "Application" #LightGreen
participant "Application" as application
end box
box "Library" #LightBlue
participant "SigV4 Library" as sigv4
end box
box "IoT Server" #Yellow
participant "IoT Server" as server
end box
box "AWS Server" #Orange
participant "AWS Server" as aws
end box
activate application
application -> server : Connect to AWS IOT Credential provider to fetch the temporary credentials
server -> application : Connected and retrieved credentials
application -> application: Parse the temporary credentials
application -> server : Disconnect from server
application -> application: Implement crypto interface hash functions.
application -> sigv4 : Convert the AWS IoT date retrieved from AWS IoT Credential Provider\n to ISO8601 format using (SigV4_AwsIotDateToIso8601) API
sigv4-> application : Date Converted and written to provided buffer
application-> aws : Connect to AWS Server for sending the HTTP request
aws->application : Connected
application -> sigv4 : Generate Authorization header using (Sigv4_GenerateHTTPAuthorization) API
application->application : Add the Authorization Header to the HTTP request to AWS Server.
application-> aws : Send the HTTP request to AWS Server to perform the desired action
aws-> application : Receive HTTP Response from AWS Server
application -> aws: Disconnect from AWS server
deactivate application
@enduml

View File

@ -0,0 +1,267 @@
accesskeyid
accesskeyidlen
addtodate
addtogroup
aggregator
algorithmlen
amz
ansi
api
apr
ascii
auth
authbuflen
authorizaton
aws
br
bufferlen
bufremaining
bytesconsumed
canonicalrequest
canonicalurilen
cbmc
chunked
com
completehashandhexencode
config
configpagestyle
const
constness
copydoc
copyheaderstringtocanonicalbuffer
coverity
credentialscope
crypto
cryptointerface
css
ctype
currentparameter
datalen
datatracker
datelen
dd
deconstructed
defgroup
doesn
doubleencodeequals
doxygen
encodeslash
encodetwice
endcode
endif
enums
expirationlen
failable
feb
formatchar
formatlen
gcc
generatecanonicaluri
github
gmt
gr
hashblocklen
hashcontext
hashdigestlen
hashedcanonicalrequest
hashfinal
hashinit
hashpayloadlen
hashtofail
hashupdate
headercount
headerindex
headerlen
headersdatalen
headerslen
hexencoded
hexstring
hh
hhmmss
hmac
hmacaddkey
hmacdata
hmacfinal
hmacintermediate
hmackey
html
http
httpmethodlen
https
ietf
ifdef
ifndef
inc
ingroup
inputchar
inputlen
iot
ipad
iskeyprefix
iso
isspace
itemsize
jan
january
keylen
ksecret
leninput
lentoread
lf
linelen
linux
logdebug
logerror
loginfo
logwarn
longregionlen
lv
maclen
mainpage
md
memcpy
memmove
min
misra
mit
mmm
mon
monthsperday
noninfringement
nullterminate
numitems
oom
opad
openssl
ored
org
outputlen
paccesskeyid
palgorithm
param
parray
pathlen
pauthbuf
pauthprefixlen
payloadlen
pbufcur
pbuffer
pbufloc
pbufprocessing
pbufstart
pbytesremaining
pcanonicalcontext
pcanonicalrequest
pcanonicaluri
pcredentials
pcredscope
pcryptointerface
pdata
pdate
pdateelements
pexpiration
pfirstitem
pfirstval
pformat
phashcontext
phashpayloadloc
pheaders
pheadersloc
phexoutput
phmaccontext
phttpmethod
phttpparameters
pinput
pinputstr
pkey
pline
pmac
png
posix
poutput
poutputexpected
poutputleapexpected
poutputlen
pparams
ppath
ppayload
pquery
pqueryloc
pre
precanonical
precanonicalized
pregion
pregion
printf
pseconditem
psecondval
psecretaccesskey
psecuritytoken
pservice
psignature
psignedheaders
psignedheaderslen
psigningkey
ptestformatfailure
puri
pvalue
querylen
quicksort
rande
readloc
regionlen
requestdatetime
rfc
sdk
sec
secretaccesskey
secretaccesskeylen
secretkey
securitytoken
securitytokenlen
sep
servicelen
sha
signaturelen
signedheaders
signedheaderslen
signingkey
sizeneededforcredentialscope
sizeof
snprintf
spdx
ss
sscanf
standalone
strftime
stringtosign
strlen
struct
structs
sts
subarray
subfolder
sublicense
thu
tm
todo
trimmable
trimmedlen
trimmedlength
trimmedlength
tue
txt
un
uri
urilen
url
utc
vallen
valuelen
writecanonicalqueryparameters
writelinetocanonicalrequest
xor
xoring
xy
yyyy
yyyymmdd

View File

@ -0,0 +1,5 @@
name : "SigV4-for-AWS-IoT-embedded-sdk"
version: "v1.2.0"
description: |
"Library used in client authorization over HTTP with AWS IoT, on embedded devices.\n"
license: "MIT"

View File

@ -0,0 +1,36 @@
SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: SigV4-for-AWS-IoT-embedded-sdk
DocumentNamespace: https://github.com/FreeRTOS/SigV4-for-AWS-IoT-embedded-sdk/blob/v1.2.0/sbom.spdx
Creator: Amazon Web Services
Created: 2022-10-14T20:15:40Z
CreatorComment: NOASSERTION
DocumentComment: NOASSERTION
PackageName: SigV4-for-AWS-IoT-embedded-sdk
SPDXID: SPDXRef-Package-SigV4-for-AWS-IoT-embedded-sdk
PackageVersion: v1.2.0
PackageDownloadLocation: https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/tree/v1.2.0
PackageLicenseConcluded: MIT
FilesAnalyzed: True
PackageVerificationCode: 8f6d21857c89b72cd4da54d9a189fb10b5321c82
PackageCopyrightText: NOASSERTION
PackageSummary: NOASSERTION
PackageDescription: "Library used in client authorization over HTTP with AWS IoT, on embedded devices.\n"
FileName: ./sigv4.c
SPDXID: SPDXRef-File-sigv4.c
FileChecksum: SHA1: b953340742ff75a3bb022b2a0afcaea36f6ed640
LicenseConcluded: MIT
FileCopyrightText: NOASSERTION
FileComment: NOASSERTION
FileName: ./sigv4_quicksort.c
SPDXID: SPDXRef-File-sigv4_quicksort.c
FileChecksum: SHA1: c0ca152e0924bd4b7a6b267fc3d53853beb4578c
LicenseConcluded: MIT
FileCopyrightText: NOASSERTION
FileComment: NOASSERTION

View File

@ -0,0 +1,15 @@
# This file sets source files and include directories to variables so that they
# can be reused from different repositories in their CMake based build system by
# including this file.
#
# Files specific to the repository such as test runner and platform tests are
# not added to the variables.
# SigV4 library source files.
set( SIGV4_SOURCES
"${CMAKE_CURRENT_LIST_DIR}/source/sigv4.c"
"${CMAKE_CURRENT_LIST_DIR}/source/sigv4_quicksort.c" )
# SigV4 library public include directories.
set( SIGV4_INCLUDE_PUBLIC_DIRS
"${CMAKE_CURRENT_LIST_DIR}/source/include" )

View File

@ -0,0 +1,574 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4.h
* @brief Interface for the SigV4 Library.
*/
#ifndef SIGV4_H_
#define SIGV4_H_
/* Standard includes. */
#include <stdint.h>
#include <stddef.h>
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* SIGV4_DO_NOT_USE_CUSTOM_CONFIG allows building of the SigV4 library without a
* config file. If a config file is provided, the SIGV4_DO_NOT_USE_CUSTOM_CONFIG
* macro must not be defined.
*/
#ifndef SIGV4_DO_NOT_USE_CUSTOM_CONFIG
#include "sigv4_config.h"
#endif
/* Include config defaults header to get default values of configurations not
* defined in sigv4_config.h file. */
#include "sigv4_config_defaults.h"
/* Convenience macros for library optimization */
/** @addtogroup sigv4_constants
* @{
*/
#define SIGV4_AWS4_HMAC_SHA256 "AWS4-HMAC-SHA256" /**< AWS identifier for SHA256 signing algorithm. */
#define SIGV4_AWS4_HMAC_SHA256_LENGTH ( sizeof( SIGV4_AWS4_HMAC_SHA256 ) - 1U ) /**< Length of AWS identifier for SHA256 signing algorithm. */
#define SIGV4_HTTP_X_AMZ_DATE_HEADER "x-amz-date" /**< AWS identifier for HTTP date header. */
#define SIGV4_HTTP_X_AMZ_SECURITY_TOKEN_HEADER "x-amz-security-token" /**< AWS identifier for security token. */
#define SIGV4_STREAMING_AWS4_HMAC_SHA256_PAYLOAD "STREAMING-AWS4-HMAC-SHA256-PAYLOAD" /**< S3 identifier for chunked payloads. */
/* MISRA Ref 5.4.1 [Macro identifiers] */
/* More details at: https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/blob/main/MISRA.md#rule-54 */
/* coverity[other_declaration] */
#define SIGV4_HTTP_X_AMZ_CONTENT_SHA256_HEADER "x-amz-content-sha256" /**< S3 identifier for streaming requests. */
#define SIGV4_HTTP_X_AMZ_CONTENT_SHA256_HEADER_LENGTH ( sizeof( SIGV4_HTTP_X_AMZ_CONTENT_SHA256_HEADER ) - 1U ) /**< Length of S3 identifier for streaming requests. */
#define SIGV4_HTTP_X_AMZ_STORAGE_CLASS_HEADER "x-amz-storage-class" /**< S3 identifier for reduced streaming redundancy. */
#define SIGV4_ACCESS_KEY_ID_LENGTH 20U /**< Length of access key ID. */
#define SIGV4_SECRET_ACCESS_KEY_LENGTH 40U /**< Length of secret access key. */
#define SIGV4_ISO_STRING_LEN 16U /**< Length of ISO 8601 date string. */
#define SIGV4_EXPECTED_LEN_RFC_3339 20U /**< Length of RFC 3339 date input. */
#define SIGV4_EXPECTED_LEN_RFC_5322 29U
/**< Length of RFC 5322 date input. */
/** @}*/
/**
* @defgroup sigv4_canonical_flags SigV4HttpParameters_t Flags
* @brief Flags for SigV4HttpParameters_t.flags. These flags inform the library
* of parameters already in canonical form.
*
* Flags should be bitwise-ORed with each other to change the behavior of
* #SigV4_GenerateHTTPAuthorization.
*/
/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request path input is already
* canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_PATH_IS_CANONICAL_FLAG 0x1U
/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request query input is already
* canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_QUERY_IS_CANONICAL_FLAG 0x2U
/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request headers input is
* already canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_HEADERS_ARE_CANONICAL_FLAG 0x4U
/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request payload is
* already hashed.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_PAYLOAD_IS_HASH 0x8U
/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request path, query, and
* headers are all already canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_ALL_ARE_CANONICAL_FLAG 0x7U
/**
* @ingroup sigv4_enum_types
* @brief Return status of the SigV4 Library.
*/
typedef enum SigV4Status
{
/**
* @brief The SigV4 library function completed successfully.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
* - #SigV4_AwsIotDateToIso8601
*/
SigV4Success,
/**
* @brief The SigV4 library function received an invalid input
* parameter.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
* - #SigV4_AwsIotDateToIso8601
*/
SigV4InvalidParameter,
/**
* @brief The application buffer was not large enough for the specified hash
* function.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
*/
SigV4InsufficientMemory,
/**
* @brief An error occurred while formatting the provided date header.
*
* Functions that may return this value:
* - #SigV4_AwsIotDateToIso8601
*/
SigV4ISOFormattingError,
/**
* @brief The maximum number of header parameters was exceeded while parsing
* the http header string passed to the library.
* The maximum number of supported HTTP headers can be configured
* with the SIGV4_MAX_HTTP_HEADER_COUNT macro in the library config file
* passed by the application.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
*/
SigV4MaxHeaderPairCountExceeded,
/**
* @brief The maximum number of query parameters was exceeded while parsing
* the query string passed to the library.
* The maximum number of supported query parameters can be configured
* with the SIGV4_MAX_QUERY_PAIR_COUNT macro in the library config file
* passed by the application.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
*/
SigV4MaxQueryPairCountExceeded,
/**
* @brief An error occurred while performing a hash operation.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
*/
SigV4HashError,
/**
* @brief HTTP headers parsed to the library are invalid.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
*/
SigV4InvalidHttpHeaders
} SigV4Status_t;
/**
* @ingroup sigv4_struct_types
* @brief The cryptography interface used to supply the user-defined hash
* implementation.
*/
typedef struct SigV4CryptoInterface
{
/**
* @brief Initializes the @p pHashContext.
*
* @param[in] pHashContext Context used to maintain the hash's current state
* during incremental updates.
*
* @return Zero on success, all other return values are failures.
*/
int32_t ( * hashInit )( void * pHashContext );
/**
* @brief Calculates an ongoing hash update (SHA-256, for example).
*
* @param[in] pHashContext Context used to maintain the hash's current state
* during incremental updates.
* @param[in] pInput Buffer holding the data to hash.
* @param[in] inputLen length of the input buffer data.
*
* @return Zero on success, all other return values are failures.
*/
int32_t ( * hashUpdate )( void * pHashContext,
const uint8_t * pInput,
size_t inputLen );
/**
* @brief Calculates the final binary digest of the hash from the context.
*
* @param[in] pHashContext Context used to maintain the hash's current state
* during incremental updates.
* @param[out] pOutput The buffer used to place final hash binary digest
* output.
* @param[in] outputLen The length of the pOutput buffer, which must be
* larger than the hash digest length specified in
* #SIGV4_HASH_MAX_DIGEST_LENGTH.
*
* @return Zero on success, all other return values are failures.
*/
int32_t ( * hashFinal )( void * pHashContext,
uint8_t * pOutput,
size_t outputLen );
/**
* @brief Context for the hashInit, hashUpdate, and hashFinal interfaces.
*/
void * pHashContext;
/**
* @brief The block length of the hash function.
*/
size_t hashBlockLen;
/**
* @brief The digest length of the hash function.
*/
size_t hashDigestLen;
} SigV4CryptoInterface_t;
/**
* @ingroup sigv4_struct_types
* @brief Configurations of the HTTP request used to create the Canonical
* Request.
*/
typedef struct SigV4HttpParameters
{
const char * pHttpMethod; /**< @brief The HTTP method: GET, POST, PUT, etc. */
size_t httpMethodLen; /**< @brief Length of pHttpMethod. */
/**
* @brief These flags are used to indicate if the path, query, or headers are already
* in the canonical form. This is to bypass the internal sorting, white space
* trimming, and encoding done by the library. This is a performance optimization
* option. Please see https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
* for information on generating a canonical path, query, and headers string.
* - #SIGV4_HTTP_PATH_IS_CANONICAL_FLAG 0x1
* - #SIGV4_HTTP_QUERY_IS_CANONICAL_FLAG 0x2
* - #SIGV4_HTTP_HEADERS_ARE_CANONICAL_FLAG 0x4
* - #SIGV4_HTTP_ALL_ARE_CANONICAL_FLAG 0x7
*/
uint32_t flags;
/**
* @brief The path in the HTTP request. This is the absolute request URI,
* which contains everything in the URI following the HTTP host until the
* question mark character ("?") that begins any query string parameters
* (e.g. "/path/to/item.txt"). If SIGV4_HTTP_PATH_IS_CANONICAL_FLAG is set,
* then this input must already be in canonical form.
*
* @note If there exists no path for the HTTP request, then this can be
* NULL.
*/
const char * pPath;
size_t pathLen; /**< @brief Length of pPath. */
/**
* @brief The HTTP request query from the URL, if it exists. This contains all
* characters following the question mark character ("?") that denotes the start
* of the query. If SIGV4_HTTP_QUERY_IS_CANONICAL_FLAG is set, then this input
* must already be in canonical form.
*
* @note If the HTTP request does not contain query string, this can
* be NULL.
*/
const char * pQuery;
size_t queryLen; /**< @brief Length of pQuery. */
/**
* @brief The headers from the HTTP request that we want to sign. This
* should be the raw headers in HTTP request format. If
* SIGV4_HTTP_HEADERS_IS_CANONICAL_FLAG is set, then this input must
* already be in canonical form.
*
* @note The headers data MUST NOT be empty. For HTTP/1.1 requests, it is
* required that the "host" header MUST be part of the SigV4 signature.
*/
const char * pHeaders;
size_t headersLen; /**< @brief Length of pHeaders. */
/**
* @brief The HTTP response body, if one exists (ex. PUT request). If this
* body is chunked, then this field should be set with
* STREAMING-AWS4-HMAC-SHA256-PAYLOAD.
*/
const char * pPayload;
size_t payloadLen; /**< @brief Length of pPayload. */
} SigV4HttpParameters_t;
/**
* @ingroup sigv4_struct_types
* @brief Configurations for the AWS credentials used to generate the Signing
* Key.
*/
typedef struct SigV4Credentials
{
/**
* @brief The pAccessKeyId MUST be at least 16 characters long
* but not more than 128 characters long.
*/
const char * pAccessKeyId;
size_t accessKeyIdLen; /**< @brief Length of pAccessKeyId. */
/**
* @brief The pSecretAccessKey MUST be at least 40 characters long.
*/
const char * pSecretAccessKey;
size_t secretAccessKeyLen; /**< @brief Length of pSecretAccessKey. */
} SigV4Credentials_t;
/**
* @ingroup sigv4_struct_types
* @brief Complete configurations required for generating "String to Sign" and
* "Signing Key" values.
*
* Consists of parameter structures #SigV4Credentials_t,
* #SigV4CryptoInterface_t, and #SigV4HttpParameters_t, along with date, region,
* and service specifications.
*/
typedef struct SigV4Parameters
{
/**
* @brief The AccessKeyId, SecretAccessKey, and SecurityToken used to
* generate the Authorization header.
*/
SigV4Credentials_t * pCredentials;
/**
* @brief The date in ISO 8601 format, e.g. "20150830T123600Z". This is
* always 16 characters long.
*/
const char * pDateIso8601;
/**
* @brief The algorithm used for SigV4 authentication. If set to NULL,
* this will automatically be set to "AWS4-HMAC-SHA256" by default.
*/
const char * pAlgorithm;
size_t algorithmLen; /**< @brief Length of pAlgorithm. */
/**
* @brief The target AWS region for the request. Please see
* https://docs.aws.amazon.com/general/latest/gr/rande.html for a list of
* region names and codes.
*/
const char * pRegion;
size_t regionLen; /**< @brief Length of pRegion. */
/**
* @brief The target AWS service for the request. The service name can be
* found as the first segment of the service endpoint. Please see
* https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html
* (https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html)
* for your service of interest.
*/
const char * pService;
size_t serviceLen; /**< @brief Length of pService. */
/**
* @brief The cryptography interface.
*/
SigV4CryptoInterface_t * pCryptoInterface;
/**
* @brief HTTP specific SigV4 parameters for canonical request calculation.
*/
SigV4HttpParameters_t * pHttpParameters;
} SigV4Parameters_t;
/**
* @brief Generates the HTTP Authorization header value.
* @note The API does not support HTTP headers containing empty HTTP header keys or values.
*
* @param[in] pParams Parameters for generating the SigV4 signature.
* @param[out] pAuthBuf Buffer to hold the generated Authorization header value.
* @param[in, out] authBufLen Input: the length of @p pAuthBuf, output: the length
* of the authorization value written to the buffer.
* @param[out] pSignature Location of the signature in the authorization string.
* @param[out] signatureLen The length of @p pSignature.
*
* @return #SigV4Success if successful, error code otherwise.
*
* <b>Example</b>
* @code{c}
* // The following example shows how to use the SigV4_GenerateHTTPAuthorization
* // function to generate the HTTP Authorization header value for HTTP requests
* // to AWS services requiring SigV4 authentication.
*
* SigV4Status_t status = SigV4Success;
*
* // Buffer to hold the authorization header.
* char pSigv4Auth[ 2048U ];
* size_t sigv4AuthLen = sizeof( pSigv4Auth );
*
* // Pointer to signature in the Authorization header that will be populated in
* // pSigv4Auth by the SigV4_GenerateHTTPAuthorization API function.
* char * signature = NULL;
* size_t signatureLen = 0;
*
* SigV4Parameters_t sigv4Params =
* {
* // Parsed temporary credentials obtained from AWS IoT Credential Provider.
* .pCredentials = &sigv4Creds,
* // Date in ISO8601 format.
* .pDateIso8601 = pDateISO8601,
* // The AWS region for the request.
* .pRegion = AWS_REGION,
* .regionLen = strlen( AWS_REGION ),
* // The AWS service for the request.
* .pService = AWS_SERVICE_NAME,
* .serviceLen = strlen( AWS_SERVICE_NAME ),
* // SigV4 crypto interface. See SigV4CryptoInterface_t interface documentation.
* .pCryptoInterface = &cryptoInterface,
* // HTTP parameters for the HTTP request to generate a SigV4 authorization header for.
* .pHttpParameters = &sigv4HttpParams
* };
*
* status = SigV4_GenerateHTTPAuthorization( &sigv4Params, pSigv4Auth, &sigv4AuthLen, &signature, &signatureLen );
*
* if( status != SigV4Success )
* {
* // Failed to generate authorization header.
* }
* @endcode
*/
/* @[declare_sigV4_generateHTTPAuthorization_function] */
SigV4Status_t SigV4_GenerateHTTPAuthorization( const SigV4Parameters_t * pParams,
char * pAuthBuf,
size_t * authBufLen,
char ** pSignature,
size_t * signatureLen );
/* @[declare_sigV4_generateHTTPAuthorization_function] */
/**
* @brief Parse the date header value from the AWS IoT response, and generate
* the formatted ISO 8601 date required for authentication.
*
* This is an optional utility function available to the application, to assist
* with formatting of the date header obtained from AWS IoT (when requesting a
* temporary token or sending a POST request).
*
* AWS SigV4 authentication requires an ISO 8601 date to be present in the
* "x-amz-date" request header, as well as in the credential scope (must be
* identical). For additional information on date handling, please see
* https://docs.aws.amazon.com/general/latest/gr/sigv4-date-handling.html.
*
* Acceptable Input Formats:
* - RFC 5322 (ex. "Thu, 18 Jan 2018 09:18:06 GMT"), the preferred format in
* HTTP 'Date' response headers. If using this format, the date parameter
* should match "***, DD 'MMM' YYYY hh:mm:ss GMT" exactly.
* - RFC 3339 (ex. "2018-01-18T09:18:06Z"), found occasionally in 'Date' and
* expiration headers. If using this format, the date parameter should match
* "YYYY-MM-DD'T'hh:mm:ss'Z'" exactly.
*
* Formatted Output:
* - The ISO8601-formatted date will be returned in the form
* "YYYYMMDD'T'HHMMSS'Z'" (ex. "20180118T091806Z").
*
* @param[in] pDate The date header (in
* [RFC 3339](https://tools.ietf.org/html/rfc3339) or
* [RFC 5322](https://tools.ietf.org/html/rfc5322) formats). An acceptable date
* header can be found in the HTTP response returned by AWS IoT. This value
* should use UTC (with no time-zone offset), and be exactly 20 or 29 characters
* in length (excluding the null character), to comply with RFC 3339 and RFC
* 5322 formats, respectively.
* @param[in] dateLen The length of the pDate header value. Must be either
* SIGV4_EXPECTED_LEN_RFC_3339 or SIGV4_EXPECTED_LEN_RFC_5322, for valid input
* parameters.
* @param[out] pDateISO8601 The formatted ISO8601-compliant date. The date value
* written to this buffer will be exactly 16 characters in length, to comply
* with the ISO8601 standard required for SigV4 authentication.
* @param[in] dateISO8601Len The length of buffer pDateISO8601. Must be at least
* SIGV4_ISO_STRING_LEN bytes, for valid input parameters.
*
* @return #SigV4Success code if successful, error code otherwise.
*
*
* <b>Example</b>
* @code{c}
* // The following example shows how to use the SigV4_AwsIotDateToIso8601
* // function to convert an AWS IoT date header value to a ISO 8601 date.
*
* SigV4Status_t status = SigV4Success;
* char pDateISO8601[SIGV4_ISO_STRING_LEN] = {0};
* size_t pDateISO8601Len = SIGV4_ISO_STRING_LEN;
*
* // pDate and dateLen are the date header and length which are parsed from
* // an AWS IoT Credential Provider HTTP response, using an HTTP library.
* status = SigV4_AwsIotDateToIso8601( pDate, dateLen, pDateISO8601, pDateISO8601Len );
*
* if( status != SigV4Success )
* {
* // Failed to parse date
* }
* @endcode
*/
/* @[declare_sigV4_awsIotDateToIso8601_function] */
SigV4Status_t SigV4_AwsIotDateToIso8601( const char * pDate,
size_t dateLen,
char * pDateISO8601,
size_t dateISO8601Len );
/* @[declare_sigV4_awsIotDateToIso8601_function] */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* SIGV4_H_ */

View File

@ -0,0 +1,257 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_config_defaults.h
* @brief The default values for configuration macros used by the SigV4 Library.
*
* @note This file should NOT be modified. If custom values are needed for any
* configuration macros, a sigv4_config.h file should be provided to the SigV4
* Library to override the default values defined in this file. To use the custom
* config file, the preprocessor macro SIGV4_DO_NOT_USE_CUSTOM_CONFIG
* must NOT be set.
*/
#ifndef SIGV4_CONFIG_DEFAULTS_H_
#define SIGV4_CONFIG_DEFAULTS_H_
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* The macro definition for SIGV4_DO_NOT_USE_CUSTOM_CONFIG is for Doxygen
* documentation only. */
/**
* @brief Define this macro to build the AWS IoT SigV4 Library without the
* custom config file sigv4_config.h.
*
* Without the custom config, the the AWS IoT SigV4 Library builds with default
* values of config macros defined in the sigv4_config_defaults.h file.
*
* If a custom config file is provided, then
* SIGV4_DO_NOT_USE_CUSTOM_CONFIG must not be defined.
*
* <b>Default value</b>: SIGV4_DO_NOT_USE_CUSTOM_CONFIG is
* <b>not</b> defined by default and the library expects a
* sigv4_config.h file.
*/
#ifdef DOXYGEN
#define SIGV4_DO_NOT_USE_CUSTOM_CONFIG
#endif
/**
* @brief Macro defining the size of the internal buffer used for incremental
* canonicalization and hashing.
*
* A buffer of this size in bytes is declared on the stack. It should be be
* large enough for the digest output of the specified hash function.
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `1024`
*/
#ifndef SIGV4_PROCESSING_BUFFER_LENGTH
#define SIGV4_PROCESSING_BUFFER_LENGTH 1024U
#endif
/**
* @brief Macro defining the maximum number of headers in the request, used to
* assist the library in sorting header fields during canonicalization.
*
* This macro should be updated if the number of request headers the application
* wishes to sign is higher or lower than the default value (100).
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `100`
*/
#ifndef SIGV4_MAX_HTTP_HEADER_COUNT
#define SIGV4_MAX_HTTP_HEADER_COUNT 100U
#endif
/**
* @brief Macro defining the maximum number of query key/value pairs, used to
* assist the library in sorting query keys during canonicalization.
*
* This macro should be updated if the number of query key/value pairs the
* application wishes to sign is higher or lower than the default value (100).
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `100`
*/
#ifndef SIGV4_MAX_QUERY_PAIR_COUNT
#define SIGV4_MAX_QUERY_PAIR_COUNT 100U
#endif
/**
* @brief Macro used to compute the worst-case stack size when sorting elements
* associated with #SIGV4_MAX_QUERY_PAIR_COUNT or #SIGV4_MAX_HTTP_HEADER_COUNT.
* Suppose the max of the two aforementioned macros is X, then the macro
* below must be set to 2 * ceiling(log(X)/log(2)) where ceiling rounds up
* the ones digit if the decimal is greater than 0.
* @note If updating #SIGV4_MAX_QUERY_PAIR_COUNT or #SIGV4_MAX_HTTP_HEADER_COUNT,
* be sure to update this value based on the formula above.
*/
#ifndef SIGV4_WORST_CASE_SORT_STACK_SIZE
#define SIGV4_WORST_CASE_SORT_STACK_SIZE 14U
#endif
/**
* @brief Macro indicating the largest block size of any hashing
* algorithm used for SigV4 authentication i.e. the maximum of all
* values specified for the hashBlockLen in #SigV4CryptoInterface_t.
* For example, using SHA-512 would require this value to be at least 128.
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `64`
*/
#ifndef SIGV4_HASH_MAX_BLOCK_LENGTH
#define SIGV4_HASH_MAX_BLOCK_LENGTH 64U
#endif
/**
* @brief Macro defining the maximum digest length of the specified hash function,
* used to determine the length of the output buffer.
*
* This macro should be updated if using a hashing algorithm other than SHA256
* (32 byte digest length). For example, using SHA512 would require this
* value to be at least 64.
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `32`
*/
#ifndef SIGV4_HASH_MAX_DIGEST_LENGTH
#define SIGV4_HASH_MAX_DIGEST_LENGTH 32U
#endif
/**
* @brief Macro to statically enable support for canonicalizing the URI,
* headers, and query in this library.
*
* Set this to one to enable the encoding functions used to create the canonical
* request.
*
* <b>Possible values:</b> 0 or 1 <br>
* <b>Default value:</b> `1`
*/
#ifndef SIGV4_USE_CANONICAL_SUPPORT
#define SIGV4_USE_CANONICAL_SUPPORT 1
#endif
/**
* @brief Macro called by the SigV4 library for logging "Error" level
* messages.
*
* To enable error level logging in the SigV4 library, this macro should
* be mapped to the application-specific logging implementation that supports
* error logging.
*
* @note This logging macro is called in the SigV4 library with
* parameters wrapped in double parentheses to be ISO C89/C90 standard
* compliant. For a reference POSIX implementation of the logging macros, refer
* to sigv4_config.h files, and the logging-stack in demos folder of the [AWS
* IoT Embedded C SDK
* repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
*
* <b>Default value</b>: Error logging is turned off, and no code is generated
* for calls to the macro in the SigV4 library on compilation.
*/
#ifndef LogError
#define LogError( message )
#endif
/**
* @brief Macro called by the the SigV4 library for logging "Warning"
* level messages.
*
* To enable warning level logging in the SigV4 library, this macro
* should be mapped to the application-specific logging implementation that
* supports warning logging.
*
* @note This logging macro is called in the SigV4 library with
* parameters wrapped in double parentheses to be ISO C89/C90 standard
* compliant. For a reference POSIX implementation of the logging macros, refer
* to sigv4_config.h files, and the logging-stack in demos folder of the [AWS
* IoT Embedded C SDK
* repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
*
* <b>Default value</b>: Warning logs are turned off, and no code is generated
* for calls to the macro in the SigV4 library on compilation.
*/
#ifndef LogWarn
#define LogWarn( message )
#endif
/**
* @brief Macro called by the the SigV4 library for logging "Info" level
* messages.
*
* To enable info level logging in the SigV4 library, this macro should
* be mapped to the application-specific logging implementation that supports
* info logging.
*
* @note This logging macro is called in the SigV4 library with
* parameters wrapped in double parentheses to be ISO C89/C90 standard
* compliant. For a reference POSIX implementation of the logging macros, refer
* to sigv4_config.h files, and the logging-stack in demos folder of the [AWS
* IoT Embedded C SDK
* repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
*
* <b>Default value</b>: Info logging is turned off, and no code is generated
* for calls to the macro in the SigV4 library on compilation.
*/
#ifndef LogInfo
#define LogInfo( message )
#endif
/**
* @brief Macro called by the the SigV4 library for logging "Debug"
* level messages.
*
* To enable debug level logging from SigV4 library, this macro should
* be mapped to the application-specific logging implementation that supports
* debug logging.
*
* @note This logging macro is called in the SigV4 library with
* parameters wrapped in double parentheses to be ISO C89/C90 standard
* compliant. For a reference POSIX implementation of the logging macros, refer
* to sigv4_config.h files, and the logging-stack in demos folder of the [AWS
* IoT Embedded C SDK
* repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
*
* <b>Default value</b>: Debug logging is turned off, and no code is generated
* for calls to the macro in the SigV4 library on compilation.
*/
#ifndef LogDebug
#define LogDebug( message )
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* ifndef SIGV4_CONFIG_DEFAULTS_H_ */

View File

@ -0,0 +1,243 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_internal.h
* @brief Internal definitions for the SigV4 Library.
*/
#ifndef SIGV4_INTERNAL_H_
#define SIGV4_INTERNAL_H_
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* SIGV4_DO_NOT_USE_CUSTOM_CONFIG allows building of the SigV4 library without a
* config file. If a config file is provided, the SIGV4_DO_NOT_USE_CUSTOM_CONFIG
* macro must not be defined.
*/
#ifndef SIGV4_DO_NOT_USE_CUSTOM_CONFIG
#include "sigv4_config.h"
#endif
/* Include config defaults header to get default values of configurations not
* defined in sigv4_config.h file. */
#include "sigv4_config_defaults.h"
/* Constants for date verification. */
#define YEAR_MIN 1900L /**< Earliest year accepted. */
#define MONTH_ASCII_LEN 3U /**< Length of month abbreviations. */
/**
* @brief Month name abbreviations for RFC 5322 date parsing.
*/
#define MONTH_NAMES { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }
/**
* @brief Number of days in each respective month.
*/
#define MONTH_DAYS { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
#define FORMAT_RFC_3339 "%4Y-%2M-%2DT%2h:%2m:%2sZ" /**< Format string to parse RFC 3339 date. */
#define FORMAT_RFC_3339_LEN sizeof( FORMAT_RFC_3339 ) - 1U /**< Length of the RFC 3339 format string. */
#define FORMAT_RFC_5322 "%3*, %2D %3M %4Y %2h:%2m:%2s GMT" /**< Format string to parse RFC 5322 date. */
#define FORMAT_RFC_5322_LEN sizeof( FORMAT_RFC_5322 ) - 1U /**< Length of the RFC 3339 format string. */
#define ISO_YEAR_LEN 4U /**< Length of year value in ISO 8601 date. */
#define ISO_NON_YEAR_LEN 2U /**< Length of non-year values in ISO 8601 date. */
#define ISO_DATE_SCOPE_LEN 8U /**< Length of date substring used in credential scope. */
/* SigV4 related string literals and lengths. */
/**
* @brief The separator between each component of the credential scope.
*/
#define CREDENTIAL_SCOPE_SEPARATOR '/'
#define CREDENTIAL_SCOPE_SEPARATOR_LEN 1U /**< The length of #CREDENTIAL_SCOPE_SEPARATOR. */
/**
* @brief The last component that terminates the credential scope.
*/
#define CREDENTIAL_SCOPE_TERMINATOR "aws4_request"
#define CREDENTIAL_SCOPE_TERMINATOR_LEN ( sizeof( CREDENTIAL_SCOPE_TERMINATOR ) - 1U ) /**< The length of #CREDENTIAL_SCOPE_TERMINATOR. */
/**
* @brief Default value when HttpParameters_t.pPath == NULL.
*/
#define HTTP_EMPTY_PATH "/"
#define HTTP_EMPTY_PATH_LEN ( sizeof( HTTP_EMPTY_PATH ) - 1U ) /**< The length of #HTTP_EMPTY_PATH. */
#define URI_ENCODED_SPECIAL_CHAR_SIZE 3U /**< The size of an encoded URI special character. */
#define URI_DOUBLE_ENCODED_EQUALS_CHAR_SIZE 5U /**< The size of the double-encoded "=" character. */
#define LINEFEED_CHAR '\n' /**< A linefeed character used to build the canonical request. */
#define LINEFEED_CHAR_LEN 1U /**< The length of #LINEFEED_CHAR. */
#define HTTP_REQUEST_LINE_ENDING "\r\n" /**< The string used in non-canonicalized HTTP headers to separate header entries in HTTP request. */
#define HTTP_REQUEST_LINE_ENDING_LEN ( sizeof( HTTP_REQUEST_LINE_ENDING ) - 1U ) /**< The length of #HTTP_REQUEST_LINE_ENDING. */
#define SPACE_CHAR ' ' /**< A linefeed character used to build the Authorization header value. */
#define SPACE_CHAR_LEN 1U /**< The length of #SPACE_CHAR. */
#define S3_SERVICE_NAME "s3" /**< S3 is the only service where the URI must only be encoded once. */
#define S3_SERVICE_NAME_LEN ( sizeof( S3_SERVICE_NAME ) - 1U ) /**< The length of #S3_SERVICE_NAME. */
#define SIGV4_HMAC_SIGNING_KEY_PREFIX "AWS4" /**< HMAC signing key prefix. */
#define SIGV4_HMAC_SIGNING_KEY_PREFIX_LEN ( sizeof( SIGV4_HMAC_SIGNING_KEY_PREFIX ) - 1U ) /**< The length of #SIGV4_HMAC_SIGNING_KEY_PREFIX. */
#define AUTH_CREDENTIAL_PREFIX "Credential=" /**< The prefix that goes before the credential value in the Authorization header value. */
#define AUTH_CREDENTIAL_PREFIX_LEN ( sizeof( AUTH_CREDENTIAL_PREFIX ) - 1U ) /**< The length of #AUTH_CREDENTIAL_PREFIX. */
#define AUTH_SEPARATOR ", " /**< The separator between each component in the Authorization header value. */
#define AUTH_SEPARATOR_LEN ( sizeof( AUTH_SEPARATOR ) - 1U ) /**< The length of #AUTH_SEPARATOR. */
#define AUTH_SIGNED_HEADERS_PREFIX "SignedHeaders=" /**< The prefix that goes before the signed headers in the Authorization header value. */
#define AUTH_SIGNED_HEADERS_PREFIX_LEN ( sizeof( AUTH_SIGNED_HEADERS_PREFIX ) - 1U ) /**< The length of #AUTH_SIGNED_HEADERS_PREFIX. */
#define AUTH_SIGNATURE_PREFIX "Signature=" /**< The prefix that goes before the signature in the Authorization header value. */
#define AUTH_SIGNATURE_PREFIX_LEN ( sizeof( AUTH_SIGNATURE_PREFIX ) - 1U ) /**< The length of #AUTH_SIGNATURE_PREFIX. */
#define HMAC_INNER_PAD_BYTE ( 0x36U ) /**< The "ipad" byte used for generating the inner key in the HMAC calculation process. */
#define HMAC_OUTER_PAD_BYTE ( 0x5CU ) /**< The "opad" byte used for generating the outer key in the HMAC calculation process. */
#define HMAX_IPAD_XOR_OPAD_BYTE ( 0x6AU ) /**< The XOR of the "ipad" and "opad" bytes to extract outer key from inner key. */
/**
* @brief A helper macro to print insufficient memory errors.
*/
#define LOG_INSUFFICIENT_MEMORY_ERROR( purposeOfWrite, bytesExceeded ) \
{ \
LogError( ( "Unable to " purposeOfWrite ": Insufficient memory configured in SIGV4_PROCESSING_BUFFER_LENGTH macro. BytesExceeded=%lu", \
( unsigned long ) ( bytesExceeded ) ) ); \
}
/**
* @brief A helper macro to test if a flag is set.
*/
#define FLAG_IS_SET( bits, flag ) ( ( ( bits ) & ( flag ) ) == ( flag ) )
/**
* @brief A helper macro to determine if a character is whitespace.
* @note The ctype function isspace() returns true for the following characters:
* ` `, `\t`, `\n`, `\v`, `\f`, `\r`. However, according to RFC5234:
* https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1
* the only whitespace characters in an HTTP header are spaces and
* horizontal tabs.
*/
#define isWhitespace( c ) ( ( ( c ) == ' ' ) || ( ( c ) == '\t' ) )
/**
* @brief An aggregator representing the individually parsed elements of the
* user-provided date parameter. This is used to verify the complete date
* representation, and construct the final ISO 8601 string.
*/
typedef struct SigV4DateTime
{
int32_t tm_year; /**< Year (1900 or later) */
int32_t tm_mon; /**< Month (1 to 12) */
int32_t tm_mday; /**< Day of Month (1 to 28/29/30/31) */
int32_t tm_hour; /**< Hour (0 to 23) */
int32_t tm_min; /**< Minutes (0 to 59) */
int32_t tm_sec; /**< Seconds (0 to 60) */
} SigV4DateTime_t;
/**
* @brief A library structure holding the string and length values of parameters to
* be sorted and standardized. This allows for a layer of abstraction during the
* canonicalization step of the V4 signing process.
*/
typedef struct SigV4String
{
char * pData; /**< SigV4 string data */
size_t dataLen; /**< Length of pData */
} SigV4String_t;
/**
* @brief A library structure holding the string and length values of parameters to
* be sorted and standardized. This allows for a layer of abstraction during the
* canonicalization step of the V4 signing process.
*/
typedef struct SigV4ConstString
{
const char * pData; /**< SigV4 string data */
size_t dataLen; /**< Length of pData */
} SigV4ConstString_t;
/**
* @brief A key-value pair data structure that allows for sorting of SigV4
* string values using internal comparison functions, and provides additional
* stability to quickSort(), to comply with Misra rule 21.9.
*/
typedef struct SigV4KeyValuePair
{
SigV4ConstString_t key; /**< SigV4 string identifier */
SigV4ConstString_t value; /**< SigV4 data */
} SigV4KeyValuePair_t;
/**
* @brief An aggregator to maintain the internal state of canonicalization
* during intermediate calculations.
*/
typedef struct CanonicalContext
{
SigV4KeyValuePair_t pQueryLoc[ SIGV4_MAX_QUERY_PAIR_COUNT ]; /**< Query pointers used during sorting. */
SigV4KeyValuePair_t pHeadersLoc[ SIGV4_MAX_HTTP_HEADER_COUNT ]; /**< Header pointers used during sorting. */
uint8_t pBufProcessing[ SIGV4_PROCESSING_BUFFER_LENGTH ]; /**< Internal calculation buffer used during canonicalization. */
char * pBufCur; /**< pBufProcessing cursor. */
size_t bufRemaining; /**< pBufProcessing value used during internal calculation. */
const char * pHashPayloadLoc; /**< Pointer used to store the location of hashed HTTP request payload. */
size_t hashPayloadLen; /**< Length of hashed HTTP request payload. */
} CanonicalContext_t;
/**
* @brief An aggregator to maintain the internal state of HMAC
* calculations.
*/
typedef struct HmacContext
{
/**
* @brief The cryptography interface.
*/
const SigV4CryptoInterface_t * pCryptoInterface;
/**
* @brief All accumulated key data.
*/
uint8_t key[ SIGV4_HASH_MAX_BLOCK_LENGTH ];
/**
* @brief The length of the accumulated key data.
*/
size_t keyLen;
} HmacContext_t;
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* ifndef SIGV4_INTERNAL_H_ */

View File

@ -0,0 +1,85 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_quicksort.h
* @brief Declaration of Quicksort function for the SigV4 Library.
*/
#ifndef SIGV4_QUICKSORT_H_
#define SIGV4_QUICKSORT_H_
/* Standard includes. */
#include <stdint.h>
#include <stddef.h>
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* SIGV4_DO_NOT_USE_CUSTOM_CONFIG allows building of the SigV4 library without a
* config file. If a config file is provided, the SIGV4_DO_NOT_USE_CUSTOM_CONFIG
* macro must not be defined.
*/
#ifndef SIGV4_DO_NOT_USE_CUSTOM_CONFIG
#include "sigv4_config.h"
#endif
/* Include config defaults header to get default values of configurations not
* defined in sigv4_config.h file. */
#include "sigv4_config_defaults.h"
/**
* @brief The comparison function used for sorting.
* @param[in] pFirstVal The first value to compare
* @param[in] pSecondVal The second value to compare
*
* @return A value less than 0 if @p pFirstVal is less than
* @p pSecondVal. Otherwise, greater than 0.
*/
typedef int32_t ( * ComparisonFunc_t )( const void * pFirstVal,
const void * pSecondVal );
/**
* @brief Perform quicksort on an array.
*
* @param[in] pArray The array to be sorted.
* @param[in] numItems The number of items in an array.
* @param[in] itemSize The amount of memory per entry in the array.
* @param[out] comparator The comparison function to determine if one item is less than another.
*/
void quickSort( void * pArray,
size_t numItems,
size_t itemSize,
ComparisonFunc_t comparator );
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* ifndef SIGV4_QUICKSORT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,248 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_quicksort.c
* @brief Implements an Iterative Quicksort Algorithm for the SigV4 Library.
*/
#include "sigv4_quicksort.h"
#include <string.h>
#include <assert.h>
/**
* @brief Push a value to the stack.
*/
#define PUSH_STACK( valueToPush, stack, index ) \
{ \
( stack )[ ( index ) ] = ( valueToPush ); \
++( index ); \
}
/**
* @brief Pop a value from the stack.
*/
#define POP_STACK( valueToPop, stack, index ) \
{ \
--( index ); \
( valueToPop ) = ( stack )[ ( index ) ]; \
}
/*-----------------------------------------------------------*/
/**
* @brief A helper function to swap the value of two pointers
* given their sizes.
*
* @param[in] pFirstItem The item to swap with @p pSecondItem.
* @param[in] pSecondItem The item to swap with @p pFirstItem.
* @param[in] itemSize The amount of memory per entry in the array.
*/
static void swap( void * pFirstItem,
void * pSecondItem,
size_t itemSize );
/**
* @brief A helper function to perform quicksort on a subarray.
*
* @param[in] pArray The array to be sorted.
* @param[in] low The low index of the array.
* @param[in] high The high index of the array.
* @param[in] itemSize The amount of memory per entry in the array.
* @param[out] comparator The comparison function to determine if one item is less than another.
*/
static void quickSortHelper( void * pArray,
size_t low,
size_t high,
size_t itemSize,
ComparisonFunc_t comparator );
/**
* @brief A helper function to partition a subarray using the last element
* of the array as the pivot. All items smaller than the pivot end up
* at its left while all items greater than end up at its right.
*
* @param[in] pArray The array to be sorted.
* @param[in] low The low index of the array.
* @param[in] high The high index of the array.
* @param[in] itemSize The amount of memory per entry in the array.
* @param[out] comparator The comparison function to determine if one item is less than another.
*
* @return The index of the pivot
*/
static size_t partition( void * pArray,
size_t low,
size_t high,
size_t itemSize,
ComparisonFunc_t comparator );
/*-----------------------------------------------------------*/
static void swap( void * pFirstItem,
void * pSecondItem,
size_t itemSize )
{
uint8_t * pFirstByte = pFirstItem;
uint8_t * pSecondByte = pSecondItem;
size_t dataSize = itemSize;
assert( pFirstItem != NULL );
assert( pSecondItem != NULL );
/* Swap one byte at a time. */
while( dataSize-- > 0U )
{
uint8_t tmp = *pFirstByte;
*pFirstByte = *pSecondByte;
++pFirstByte;
*pSecondByte = tmp;
++pSecondByte;
}
}
static void quickSortHelper( void * pArray,
size_t low,
size_t high,
size_t itemSize,
ComparisonFunc_t comparator )
{
size_t stack[ SIGV4_WORST_CASE_SORT_STACK_SIZE ];
/* Low and high are first two items on the stack. Note
* that we use an intermediary variable for MISRA compliance. */
size_t top = 0U, lo = low, hi = high;
PUSH_STACK( lo, stack, top );
PUSH_STACK( hi, stack, top );
while( top > 0U )
{
size_t partitionIndex;
size_t len1, len2;
POP_STACK( hi, stack, top );
POP_STACK( lo, stack, top );
partitionIndex = partition( pArray, lo, hi, itemSize, comparator );
/* Calculate length of the left partition containing items smaller
* than the pivot element.
* The length is zero if either:
* 1. The pivoted item is the smallest in the the array before partitioning.
* OR
* 2. The left partition is only of single length which can be treated as
* sorted, and thus, of zero length for avoided adding to the stack. */
len1 = ( ( partitionIndex != 0U ) && ( ( partitionIndex - 1U ) > lo ) ) ? ( partitionIndex - lo ) : 0U;
/* Calculate length of the right partition containing items greater than
* or equal to the pivot item.
* The calculated length is zero if either:
* 1. The pivoted item is the greatest in the the array before partitioning.
* OR
* 2. The right partition contains only a single length which can be treated as
* sorted, and thereby, of zero length to avoid adding to the stack. */
len2 = ( ( partitionIndex + 1U ) < hi ) ? ( hi - partitionIndex ) : 0U;
/* Push the information of the left and right partitions to the stack.
* Note: For stack space optimization, the larger of the partitions is pushed
* first and the smaller is pushed later so that the smaller part of the tree
* is completed first without increasing stack space usage before coming back
* to the larger partition. */
if( len1 > len2 )
{
PUSH_STACK( lo, stack, top );
PUSH_STACK( partitionIndex - 1U, stack, top );
if( len2 > 0U )
{
PUSH_STACK( partitionIndex + 1U, stack, top );
PUSH_STACK( hi, stack, top );
}
}
else
{
if( len2 > 0U )
{
PUSH_STACK( partitionIndex + 1U, stack, top );
PUSH_STACK( hi, stack, top );
}
if( len1 > 0U )
{
PUSH_STACK( lo, stack, top );
PUSH_STACK( partitionIndex - 1U, stack, top );
}
}
}
}
static size_t partition( void * pArray,
size_t low,
size_t high,
size_t itemSize,
ComparisonFunc_t comparator )
{
uint8_t * pivot;
uint8_t * pArrayLocal = ( uint8_t * ) pArray;
size_t i = low - 1U, j = low;
assert( pArray != NULL );
assert( comparator != NULL );
/* Choose pivot as the highest indexed item in the current partition. */
pivot = pArrayLocal + ( high * itemSize );
/* Iterate over all elements of the current array to partition it
* in comparison to the chosen pivot with smaller items on the left
* and larger or equal to items on the right. */
for( ; j < high; j++ )
{
/* Use comparator function to check current element is smaller than the pivot */
if( comparator( pArrayLocal + ( j * itemSize ), pivot ) < 0 )
{
++i;
swap( pArrayLocal + ( i * itemSize ), pArrayLocal + ( j * itemSize ), itemSize );
}
}
/* Place the pivot between the smaller and larger item chunks of
* the array. This represents the 2 partitions of the array. */
swap( pArrayLocal + ( ( i + 1U ) * itemSize ), pivot, itemSize );
/* Return the pivot item's index. */
return i + 1U;
}
void quickSort( void * pArray,
size_t numItems,
size_t itemSize,
ComparisonFunc_t comparator )
{
assert( pArray != NULL );
assert( numItems > 0U );
assert( itemSize > 0U );
assert( comparator != NULL );
quickSortHelper( pArray, 0U, numItems - 1U, itemSize, comparator );
}

View File

@ -0,0 +1,89 @@
# Project information.
cmake_minimum_required( VERSION 3.13.0 )
project( "SigV4 unit test"
LANGUAGES C )
# Allow the project to be organized into folders.
set_property( GLOBAL PROPERTY USE_FOLDERS ON )
set( CMAKE_C_STANDARD_REQUIRED ON )
# Do not allow in-source build.
if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} )
message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." )
endif()
# Set global path variables.
get_filename_component( __MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE )
set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "SigV4 repository root." )
# Configure options to always show in CMake GUI.
option( BUILD_UNIT_TESTS
"Set this to ON to enable unit tests. If the submodule for CMock testing framework is not cloned, it will be auto-cloned."
OFF )
# Set output directories.
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
# ====================== Coverity Analysis Configuration ======================
# Include filepaths for source and include.
include( ${MODULE_ROOT_DIR}/sigv4FilePaths.cmake )
# Target for Coverity analysis that builds the library.
add_library( coverity_analysis
${SIGV4_SOURCES} )
# Verify ISO C90 compliance of libray.
target_compile_options( coverity_analysis PUBLIC -std=c90 )
# SigV4 public include path and test config file
target_include_directories( coverity_analysis
PUBLIC
${SIGV4_INCLUDE_PUBLIC_DIRS}
"${CMAKE_CURRENT_LIST_DIR}/include" )
# Build without debug enabled when performing static analysis
target_compile_options(coverity_analysis PUBLIC -DNDEBUG -DDISABLE_LOGGING)
# ============================ Test Configuration ============================
if(${BUILD_UNIT_TESTS})
# Define a CMock resource path.
set( CMOCK_DIR ${MODULE_ROOT_DIR}/test/unit-test/CMock CACHE INTERNAL "CMock library source directory." )
# Include CMock build configuration.
include( unit-test/cmock_build.cmake )
# Check if the CMock source directory exists, and if not present, clone the submodule
# if BUILD_CLONE_SUBMODULES configuration is enabled.
if( NOT EXISTS ${CMOCK_DIR}/src )
# Attempt to clone CMock.
clone_cmock()
endif()
# Add unit test and coverage configuration.
# Use CTest utility for managing test runs. This has to be added BEFORE
# defining test targets with add_test()
enable_testing()
# Add build targets for CMock and Unit, required for unit testing.
add_cmock_targets()
# Add function to enable CMock based tests and coverage.
include( ${MODULE_ROOT_DIR}/tools/cmock/create_test.cmake )
# Include build configuration for unit tests.
add_subdirectory( unit-test )
# ==================== Coverage Analysis configuration ========================
# Add a target for running coverage on tests.
add_custom_target( coverage
COMMAND ${CMAKE_COMMAND} -DCMOCK_DIR=${CMOCK_DIR}
-P ${MODULE_ROOT_DIR}/tools/cmock/coverage.cmake
DEPENDS cmock unity sigv4_utest
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()

View File

@ -0,0 +1,24 @@
# Emitted when running CBMC proofs
proofs/**/logs
proofs/**/gotos
proofs/**/report
proofs/**/html
proofs/output
# Emitted by CBMC Viewer
TAGS-*
# Emitted by Arpa
arpa_cmake/
arpa-validation-logs/
Makefile.arpa
# Emitted by litani
.ninja_deps
.ninja_log
.litani_cache_dir
# These files should be overwritten whenever prepare.py runs
cbmc-batch.yaml
__pycache__/

View File

@ -0,0 +1,6 @@
CBMC proof include files
========================
This directory contains include files written for CBMC proof. It is
common to write some code to model aspects of the system under test,
and the header files for this code go here.

View File

@ -0,0 +1,49 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file hash_stubs.h
* @brief Declarations for stubs used in sigv4.c.
* Please see sigv4.c for documentation.
*/
#ifndef HASH_STUBS_H_
#define HASH_STUBS_H_
/* Standard includes. */
#include <stdint.h>
#include <stddef.h>
#include <string.h>
int32_t HashInitStub( void * pHashContext );
int32_t HashUpdateStub( void * pHashContext,
const char * pInput,
size_t inputLen );
int32_t HashFinalStub( void * pHashContext,
const char * pInput,
size_t inputLen );
#endif /* ifndef HASH_STUBS_H_ */

View File

@ -0,0 +1,42 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SIGV4_ANNEX_H_
#define SIGV4_ANNEX_H_
#include "sigv4.h"
#include "sigv4_internal.h"
/*
* These are declarations for the (normally) static functions from sigv4.c.
* Please see sigv4.c for documentation.
*/
SigV4Status_t copyHeaderStringToCanonicalBuffer( const char * pData,
size_t dataLen,
uint32_t flags,
char separator,
CanonicalContext_t * canonicalRequest );
#endif /* ifndef SIGV4_ANNEX_H_ */

View File

@ -0,0 +1,105 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_config.h
* @brief The default values for configuration macros used by the SigV4 Library.
*
* @note This file should NOT be modified. If custom values are needed for any
* configuration macros, a sigv4_config.h file should be provided to the SigV4
* Library to override the default values defined in this file. To use
* the custom config file, the preprocessor macro SIGV4_DO_NOT_USE_CUSTOM_CONFIG
* must NOT be set.
*/
#ifndef SIGV4_CONFIG_H_
#define SIGV4_CONFIG_H_
/**
* @brief Macro indicating the largest block size of any hashing
* algorithm used for SigV4 authentication i.e. the maximum of all
* values specified for the hashBlockLen in #SigV4CryptoInterface_t.
* For example, using SHA-512 would require this value to be at least 128.
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `64`
*/
#define SIGV4_HASH_MAX_BLOCK_LENGTH ( MAX_HASH_BLOCK_LEN - 1U )
/**
* @brief Macro defining the maximum digest length of the specified hash function,
* used to determine the length of the output buffer.
*
* This macro should be updated if using a hashing algorithm other than SHA256
* (32 byte digest length). For example, using SHA512 would require this
* value to be at least 64.
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `32`
*/
#define SIGV4_HASH_MAX_DIGEST_LENGTH ( MAX_HASH_DIGEST_LEN - 1U )
/**
* @brief Macro defining the size of the internal buffer used for incremental
* canonicalization and hashing.
*
* A buffer of this size in bytes is declared on the stack. It should be be
* large enough for the digest output of the specified hash function.
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `1024`
*/
#ifndef SIGV4_PROCESSING_BUFFER_LENGTH
#define SIGV4_PROCESSING_BUFFER_LENGTH 60U
#endif
/**
* @brief Macro defining the maximum number of headers in the request, used to
* assist the library in sorting header fields during canonicalization.
*
* This macro should be updated if the number of request headers the application
* wishes to sign is higher or lower than the default value (100).
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `100`
*/
#ifndef SIGV4_MAX_HTTP_HEADER_COUNT
#define SIGV4_MAX_HTTP_HEADER_COUNT 5U
#endif
/**
* @brief Macro defining the maximum number of query key/value pairs, used to
* assist the library in sorting query keys during canonicalization.
*
* This macro should be updated if the number of query key/value pairs the
* application wishes to sign is higher or lower than the default value (100).
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `100`
*/
#ifndef SIGV4_MAX_QUERY_PAIR_COUNT
#define SIGV4_MAX_QUERY_PAIR_COUNT 5U
#endif
#endif /* ifndef SIGV4_CONFIG_H_ */

View File

@ -0,0 +1,77 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_stubs.h
* @brief Declarations for the (normally) static functions from sigv4.c.
* Please see sigv4.c for documentation.
*/
#ifndef SIGV4_STUBS_H_
#define SIGV4_STUBS_H_
#include <stdbool.h>
#include <sigv4.h>
#include <sigv4_internal.h>
void addToDate( const char formatChar,
int32_t result,
SigV4DateTime_t * pDateElements );
SigV4Status_t scanValue( const char * pDate,
const char formatChar,
size_t readLoc,
size_t lenToRead,
SigV4DateTime_t * pDateElements );
SigV4Status_t writeLineToCanonicalRequest( const char * pLine,
size_t lineLen,
CanonicalContext_t * pCanonicalContext );
SigV4Status_t encodeURI( const char * pUri,
size_t uriLen,
char * pCanonicalURI,
size_t * canonicalURILen,
bool encodeSlash,
bool doubleEncodeEquals );
SigV4Status_t generateCanonicalQuery( const char * pQuery,
size_t queryLen,
CanonicalContext_t * pCanonicalContext );
SigV4Status_t generateCanonicalAndSignedHeaders( const char * pHeaders,
size_t headersLen,
uint32_t flags,
CanonicalContext_t * canonicalRequest,
char ** pSignedHeaders,
size_t * pSignedHeadersLen );
SigV4Status_t copyHeaderStringToCanonicalBuffer( const char * pData,
size_t dataLen,
uint32_t flags,
char separator,
CanonicalContext_t * canonicalRequest );
#endif /* ifndef SIGV4_STUBS_H_ */

View File

@ -0,0 +1,23 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
HARNESS_ENTRY=harness
DEFINES += -DCBMC_MAX_BUFSIZE=$(CBMC_MAX_BUFSIZE)
ifdef CBMC_MAX_QUERYKEYLENGTH
DEFINES += -DCBMC_MAX_QUERYKEYLENGTH=$(CBMC_MAX_QUERYKEYLENGTH)
endif
INCLUDES += -I$(CBMC_ROOT)/include
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROJECT_SOURCES += $(PROOFDIR)/sigv4.c
PROJECT_SOURCES += $(SRCDIR)/source/sigv4_quicksort.c
CHECKFLAGS += --pointer-primitive-check
include ../Makefile.common
cleanclean: veryclean
-$(RM) $(PROOFDIR)/sigv4.c

View File

@ -0,0 +1,43 @@
# -*- mode: makefile -*-
# The first line sets the emacs major mode to Makefile
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
################################################################
# Use this file to give project-specific definitions of the command
# line arguments to pass to CBMC tools like goto-cc to build the goto
# binaries and cbmc to do the property and coverage checking.
#
# Use this file to override most default definitions of variables in
# Makefile.common.
################################################################
# Flags to pass to goto-cc for compilation (typically those passed to gcc -c)
# COMPILE_FLAGS =
COMPILE_FLAGS += -fPIC
COMPILE_FLAGS += -std=gnu90
# Flags to pass to goto-cc for linking (typically those passed to gcc)
# LINK_FLAGS =
# Preprocessor include paths -I...
# Consider adding
# INCLUDES += -I$(CBMC_ROOT)/include
# You will want to decide what order that comes in relative to the other
# include directories in your project.
#
# INCLUDES =
INCLUDES += -I$(SRCDIR)/test/cbmc/include
INCLUDES += -I$(SRCDIR)/source/include
INCLUDES += -I$(SRCDIR)/test/include
# Preprocessor definitions -D...
# DEFINES =
DEFINES +=
# Path to arpa executable
# ARPA =
# Flags to pass to cmake for building the project
# ARPA_CMAKE_FLAGS =

View File

@ -0,0 +1,25 @@
# -*- mode: makefile -*-
# The first line sets the emacs major mode to Makefile
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
################################################################
# Use this file to give project-specific targets, including targets
# that may depend on targets defined in Makefile.common.
################################################################
# Each proof requires sigv4.c to be patched (using sed) and dumped into the
# proof directory. The exact sed invocation differs for each proof. So each
# proof must set the SIGV4_SED_EXPR variable, which this rule uses as the
# argument to sed.
$(PROOFDIR)/sigv4.c: $(SRCDIR)/source/sigv4.c
$(LITANI) add-job \
--command \
"sed -E '$(SIGV4_SED_EXPR)' $^" \
--inputs $^ \
--outputs $@ \
--stdout-file $@ \
--ci-stage build \
--pipeline-name "$(PROOF_UID)" \
--description "$(PROOF_UID): patching sigv4.c"

View File

@ -0,0 +1,11 @@
# -*- mode: makefile -*-
# The first line sets the emacs major mode to Makefile
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
################################################################
# Use this file to define project-specific targets and definitions for
# unit testing or continuous integration that may depend on targets
# defined in Makefile.common
################################################################

View File

@ -0,0 +1,19 @@
PROOF_ROOT ?= $(abspath .)
# Absolute path to the root of the source tree.
#
SRCDIR ?= $(abspath $(PROOF_ROOT)/../../..)
# Absolute path to the litani script.
#
LITANI ?= litani
# Name of this proof project, displayed in proof reports. For example,
# "s2n" or "Amazon FreeRTOS". For projects with multiple proof roots,
# this may be overridden on the command-line to Make, for example
#
# make PROJECT_NAME="FreeRTOS MQTT" report
#
PROJECT_NAME = "sigv4-for-aws-iot-embedded-sdk"

View File

@ -0,0 +1,999 @@
# -*- mode: makefile -*-
# The first line sets the emacs major mode to Makefile
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
CBMC_STARTER_KIT_VERSION = CBMC starter kit 2.5
################################################################
# The CBMC Starter Kit depends on the files Makefile.common and
# run-cbmc-proofs.py. They are installed by the setup script
# cbmc-starter-kit-setup and updated to the latest version by the
# update script cbmc-starter-kit-update. For more information about
# the starter kit and these files and these scripts, see
# https://model-checking.github.io/cbmc-starter-kit
#
# Makefile.common implements what we consider to be some best
# practices for using cbmc for software verification.
#
# Section I gives default values for a large number of Makefile
# variables that control
# * how your code is built (include paths, etc),
# * what program transformations are applied to your code (loop
# unwinding, etc), and
# * what properties cbmc checks for in your code (memory safety, etc).
#
# These variables are defined below with definitions of the form
# VARIABLE ?= DEFAULT_VALUE
# meaning VARIABLE is set to DEFAULT_VALUE if VARIABLE has not already
# been given a value.
#
# For your project, you can override these default values with
# project-specific definitions in Makefile-project-defines.
#
# For any individual proof, you can override these default values and
# project-specific values with proof-specific definitions in the
# Makefile for your proof.
#
# The definitions in the proof Makefile override definitions in the
# project Makefile-project-defines which override definitions in this
# Makefile.common.
#
# Section II uses the values defined in Section I to build your code, run
# your proof, and build a report of your results. You should not need
# to modify or override anything in Section II, but you may want to
# read it to understand how the values defined in Section I control
# things.
#
# To use Makefile.common, set variables as described above as needed,
# and then for each proof,
#
# * Create a subdirectory <DIR>.
# * Write a proof harness (a function) with the name <HARNESS_ENTRY>
# in a file with the name <DIR>/<HARNESS_FILE>.c
# * Write a makefile with the name <DIR>/Makefile that looks
# something like
#
# HARNESS_FILE=<HARNESS_FILE>
# HARNESS_ENTRY=<HARNESS_ENTRY>
# PROOF_UID=<PROOF_UID>
#
# PROJECT_SOURCES += $(SRCDIR)/libraries/api_1.c
# PROJECT_SOURCES += $(SRCDIR)/libraries/api_2.c
#
# PROOF_SOURCES += $(PROOFDIR)/harness.c
# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_a.c
# PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_b.c
#
# UNWINDSET += foo.0:3
# UNWINDSET += bar.1:6
#
# REMOVE_FUNCTION_BODY += api_stub_a
# REMOVE_FUNCTION_BODY += api_stub_b
#
# DEFINES = -DDEBUG=0
#
# include ../Makefile.common
#
# * Change directory to <DIR> and run make
#
# The proof setup script cbmc-starter-kit-setup-proof from the CBMC
# Starter Kit will do most of this for, creating a directory and
# writing a basic Makefile and proof harness into it that you can edit
# as described above.
#
# Warning: If you get results that are hard to explain, consider
# running "make clean" or "make veryclean" before "make" if you get
# results that are hard to explain. Dependency handling in this
# Makefile.common may not be perfect.
SHELL=/bin/bash
default: report
################################################################
################################################################
## Section I: This section gives common variable definitions.
##
## Override these definitions in Makefile-project-defines or
## your proof Makefile.
##
## Remember that Makefile.common and Makefile-project-defines are
## included into the proof Makefile in your proof directory, so all
## relative pathnames defined there should be relative to your proof
## directory.
################################################################
# Define the layout of the source tree and the proof subtree
#
# Generally speaking,
#
# SRCDIR = the root of the repository
# CBMC_ROOT = /srcdir/cbmc
# PROOF_ROOT = /srcdir/cbmc/proofs
# PROOF_SOURCE = /srcdir/cbmc/sources
# PROOF_INCLUDE = /srcdir/cbmc/include
# PROOF_STUB = /srcdir/cbmc/stubs
# PROOFDIR = the directory containing the Makefile for your proof
#
# The path /srcdir/cbmc used in the example above is determined by the
# setup script cbmc-starter-kit-setup. Projects usually create a cbmc
# directory somewhere in the source tree, and run the setup script in
# that directory. The value of CBMC_ROOT becomes the absolute path to
# that directory.
#
# The location of that cbmc directory in the source tree affects the
# definition of SRCDIR, which is defined in terms of the relative path
# from a proof directory to the repository root. The definition is
# usually determined by the setup script cbmc-starter-kit-setup and
# written to Makefile-template-defines, but you can override it for a
# project in Makefile-project-defines and for a specific proof in the
# Makefile for the proof.
# Absolute path to the directory containing this Makefile.common
# See https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make_17.html
#
# Note: We compute the absolute paths to the makefiles in MAKEFILE_LIST
# before we filter the list of makefiles for %/Makefile.common.
# Otherwise an invocation of the form "make -f Makefile.common" will set
# MAKEFILE_LIST to "Makefile.common" which will fail to match the
# pattern %/Makefile.common.
#
MAKEFILE_PATHS = $(foreach makefile,$(MAKEFILE_LIST),$(abspath $(makefile)))
PROOF_ROOT = $(dir $(filter %/Makefile.common,$(MAKEFILE_PATHS)))
CBMC_ROOT = $(shell dirname $(PROOF_ROOT))
PROOF_SOURCE = $(CBMC_ROOT)/sources
PROOF_INCLUDE = $(CBMC_ROOT)/include
PROOF_STUB = $(CBMC_ROOT)/stubs
# Project-specific definitions to override default definitions below
# * Makefile-project-defines will never be overwritten
# * Makefile-template-defines may be overwritten when the starter
# kit is updated
sinclude $(PROOF_ROOT)/Makefile-project-defines
sinclude $(PROOF_ROOT)/Makefile-template-defines
# SRCDIR is the path to the root of the source tree
# This is a default definition that is frequently overridden in
# another Makefile, see the discussion of SRCDIR above.
SRCDIR ?= $(abspath ../..)
# PROOFDIR is the path to the directory containing the proof harness
PROOFDIR ?= $(abspath .)
################################################################
# Define how to run CBMC
# Do property checking with the external SAT solver given by
# EXTERNAL_SAT_SOLVER. Do coverage checking with the default solver,
# since coverage checking requires the use of an incremental solver.
# The EXTERNAL_SAT_SOLVER variable is typically set (if it is at all)
# as an environment variable or as a makefile variable in
# Makefile-project-defines.
#
# For a particular proof, if the default solver is faster, do property
# checking with the default solver by including this definition in the
# proof Makefile:
# USE_EXTERNAL_SAT_SOLVER =
#
ifneq ($(strip $(EXTERNAL_SAT_SOLVER)),)
USE_EXTERNAL_SAT_SOLVER ?= --external-sat-solver $(EXTERNAL_SAT_SOLVER)
endif
CHECKFLAGS += $(USE_EXTERNAL_SAT_SOLVER)
# Job pools
# For version of Litani that are new enough (where `litani print-capabilities`
# prints "pools"), proofs for which `EXPENSIVE = true` is set can be added to a
# "job pool" that restricts how many expensive proofs are run at a time. All
# other proofs will be built in parallel as usual.
#
# In more detail: all compilation, instrumentation, and report jobs are run with
# full parallelism as usual, even for expensive proofs. The CBMC jobs for
# non-expensive proofs are also run in parallel. The only difference is that the
# CBMC safety checks and coverage checks for expensive proofs are run with a
# restricted parallelism level. At any one time, only N of these jobs are run at
# once, amongst all the proofs.
#
# To configure N, Litani needs to be initialized with a pool called "expensive".
# For example, to only run two CBMC safety/coverage jobs at a time from amongst
# all the proofs, you would initialize litani like
# litani init --pools expensive:2
# The run-cbmc-proofs.py script takes care of this initialization through the
# --expensive-jobs-parallelism flag.
#
# To enable this feature, set
# the ENABLE_POOLS variable when running Make, like
# `make ENABLE_POOLS=true report`
# The run-cbmc-proofs.py script takes care of this through the
# --restrict-expensive-jobs flag.
ifeq ($(strip $(ENABLE_POOLS)),)
POOL =
else ifeq ($(strip $(EXPENSIVE)),)
POOL =
else
POOL = --pool expensive
endif
# Similar to the pool feature above. If Litani is new enough, enable
# profiling CBMC's memory use.
ifeq ($(strip $(ENABLE_MEMORY_PROFILING)),)
MEMORY_PROFILING =
else
MEMORY_PROFILING = --profile-memory
endif
# Property checking flags
#
# Each variable below controls a specific property checking flag
# within CBMC. If desired, a property flag can be disabled within
# a particular proof by nulling the corresponding variable. For
# instance, the following line:
#
# CHECK_FLAG_POINTER_CHECK =
#
# would disable the --pointer-check CBMC flag within:
# * an entire project when added to Makefile-project-defines
# * a specific proof when added to the harness Makefile
CBMC_FLAG_MALLOC_MAY_FAIL ?= --malloc-may-fail
CBMC_FLAG_MALLOC_FAIL_NULL ?= --malloc-fail-null
CBMC_FLAG_BOUNDS_CHECK ?= --bounds-check
CBMC_FLAG_CONVERSION_CHECK ?= --conversion-check
CBMC_FLAG_DIV_BY_ZERO_CHECK ?= --div-by-zero-check
CBMC_FLAG_FLOAT_OVERFLOW_CHECK ?= --float-overflow-check
CBMC_FLAG_NAN_CHECK ?= --nan-check
CBMC_FLAG_POINTER_CHECK ?= --pointer-check
CBMC_FLAG_POINTER_OVERFLOW_CHECK ?= --pointer-overflow-check
CBMC_FLAG_POINTER_PRIMITIVE_CHECK ?= --pointer-primitive-check
CBMC_FLAG_SIGNED_OVERFLOW_CHECK ?= --signed-overflow-check
CBMC_FLAG_UNDEFINED_SHIFT_CHECK ?= --undefined-shift-check
CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK ?= --unsigned-overflow-check
CBMC_FLAG_UNWINDING_ASSERTIONS ?= --unwinding-assertions
CBMC_FLAG_UNWIND ?= --unwind 1
CBMC_FLAG_FLUSH ?= --flush
# CBMC flags used for property checking and coverage checking
CBMCFLAGS += $(CBMC_FLAG_UNWIND) $(CBMC_UNWINDSET) $(CBMC_FLAG_FLUSH)
# CBMC flags used for property checking
CHECKFLAGS += $(CBMC_FLAG_MALLOC_MAY_FAIL)
CHECKFLAGS += $(CBMC_FLAG_MALLOC_FAIL_NULL)
CHECKFLAGS += $(CBMC_FLAG_BOUNDS_CHECK)
CHECKFLAGS += $(CBMC_FLAG_CONVERSION_CHECK)
CHECKFLAGS += $(CBMC_FLAG_DIV_BY_ZERO_CHECK)
CHECKFLAGS += $(CBMC_FLAG_FLOAT_OVERFLOW_CHECK)
CHECKFLAGS += $(CBMC_FLAG_NAN_CHECK)
CHECKFLAGS += $(CBMC_FLAG_POINTER_CHECK)
CHECKFLAGS += $(CBMC_FLAG_POINTER_OVERFLOW_CHECK)
CHECKFLAGS += $(CBMC_FLAG_POINTER_PRIMITIVE_CHECK)
CHECKFLAGS += $(CBMC_FLAG_SIGNED_OVERFLOW_CHECK)
CHECKFLAGS += $(CBMC_FLAG_UNDEFINED_SHIFT_CHECK)
CHECKFLAGS += $(CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK)
CHECKFLAGS += $(CBMC_FLAG_UNWINDING_ASSERTIONS)
# CBMC flags used for coverage checking
COVERFLAGS += $(CBMC_FLAG_MALLOC_MAY_FAIL)
COVERFLAGS += $(CBMC_FLAG_MALLOC_FAIL_NULL)
# Additional CBMC flag to CBMC control verbosity.
#
# Meaningful values are
# 0 none
# 1 only errors
# 2 + warnings
# 4 + results
# 6 + status/phase information
# 8 + statistical information
# 9 + progress information
# 10 + debug info
#
# Uncomment the following line or set in Makefile-project-defines
# CBMC_VERBOSITY ?= --verbosity 4
# Additional CBMC flag to control how CBMC treats static variables.
#
# NONDET_STATIC is a list of flags of the form --nondet-static
# and --nondet-static-exclude VAR. The --nondet-static flag causes
# CBMC to initialize static variables with unconstrained value
# (ignoring initializers and default zero-initialization). The
# --nondet-static-exclude VAR excludes VAR for the variables
# initialized with unconstrained values.
NONDET_STATIC ?=
# Flags to pass to goto-cc for compilation and linking
COMPILE_FLAGS ?= -Wall
LINK_FLAGS ?= -Wall
EXPORT_FILE_LOCAL_SYMBOLS ?= --export-file-local-symbols
# Preprocessor include paths -I...
INCLUDES ?=
# Preprocessor definitions -D...
DEFINES ?=
# CBMC object model
#
# CBMC_OBJECT_BITS is the number of bits in a pointer CBMC uses for
# the id of the object to which a pointer is pointing. CBMC uses 8
# bits for the object id by default. The remaining bits in the pointer
# are used for offset into the object. This limits the size of the
# objects that CBMC can model. This Makefile defines this bound on
# object size to be CBMC_MAX_OBJECT_SIZE. You are likely to get
# unexpected results if you try to malloc an object larger than this
# bound.
CBMC_OBJECT_BITS ?= 8
# CBMC loop unwinding (Normally set in the proof Makefile)
#
# UNWINDSET is a list of pairs of the form foo.1:4 meaning that
# CBMC should unwind loop 1 in function foo no more than 4 times.
# For historical reasons, the number 4 is one more than the number
# of times CBMC actually unwinds the loop.
UNWINDSET ?=
# CBMC early loop unwinding (Normally set in the proof Makefile)
#
# Most users can ignore this variable.
#
# This variable exists to support the use of loop and function
# contracts, two features under development for CBMC. Checking the
# assigns clause for function contracts and loop invariants currently
# assumes loop-free bodies for loops and functions with contracts
# (possibly after replacing nested loops with their own loop
# contracts). To satisfy this requirement, it may be necessary to
# unwind some loops before the function contract and loop invariant
# transformations are applied to the goto program. This variable
# EARLY_UNWINDSET is identical to UNWINDSET, and we assume that the
# loops mentioned in EARLY_UNWINDSET and UNWINDSET are disjoint.
EARLY_UNWINDSET ?=
# CBMC function removal (Normally set set in the proof Makefile)
#
# REMOVE_FUNCTION_BODY is a list of function names. CBMC will "undefine"
# the function, and CBMC will treat the function as having no side effects
# and returning an unconstrained value of the appropriate return type.
# The list should include the names of functions being stubbed out.
REMOVE_FUNCTION_BODY ?=
# CBMC function pointer restriction (Normally set in the proof Makefile)
#
# RESTRICT_FUNCTION_POINTER is a list of function pointer restriction
# instructions of the form:
#
# <fun_id>.function_pointer_call.<N>/<fun_id>[,<fun_id>]*
#
# The function pointer call number <N> in the specified function gets
# rewritten to a case switch over a finite list of functions.
# If some possible target functions are omitted from the list a counter
# example trace will be found by CBMC, i.e. the transformation is sound.
# If the target functions are file-local symbols, then mangled names must
# be used.
RESTRICT_FUNCTION_POINTER ?=
# The project source files (Normally set set in the proof Makefile)
#
# PROJECT_SOURCES is the list of project source files to compile,
# including the source file defining the function under test.
PROJECT_SOURCES ?=
# The proof source files (Normally set in the proof Makefile)
#
# PROOF_SOURCES is the list of proof source files to compile, including
# the proof harness, and including any function stubs being used.
PROOF_SOURCES ?=
# The number of seconds that CBMC should be allowed to run for before
# being forcefully terminated. Currently, this is set to be less than
# the time limit for a CodeBuild job, which is eight hours. If a proof
# run takes longer than the time limit of the CI environment, the
# environment will halt the proof run without updating the Litani
# report, making the proof run appear to "hang".
CBMC_TIMEOUT ?= 21600
# Proof writers could add function contracts in their source code.
# These contracts are ignored by default, but may be enabled in two distinct
# contexts using the following two variables:
# 1. To check whether one or more function contracts are sound with respect to
# the function implementation, CHECK_FUNCTION_CONTRACTS should be a list of
# function names.
# 2. To replace calls to certain functions with their correspondent function
# contracts, USE_FUNCTION_CONTRACTS should be a list of function names.
# One must check separately whether a function contract is sound before
# replacing it in calling contexts.
CHECK_FUNCTION_CONTRACTS ?=
CBMC_CHECK_FUNCTION_CONTRACTS := $(patsubst %,--enforce-contract %, $(CHECK_FUNCTION_CONTRACTS))
USE_FUNCTION_CONTRACTS ?=
CBMC_USE_FUNCTION_CONTRACTS := $(patsubst %,--replace-call-with-contract %, $(USE_FUNCTION_CONTRACTS))
# Similarly, proof writers could also add loop contracts in their source code
# to obtain unbounded correctness proofs. Unlike function contracts, loop
# contracts are not reusable and thus are checked and used simultaneously.
# These contracts are also ignored by default, but may be enabled by setting
# the APPLY_LOOP_CONTRACTS variable to 1.
APPLY_LOOP_CONTRACTS ?= 0
ifeq ($(APPLY_LOOP_CONTRACTS),1)
CBMC_APPLY_LOOP_CONTRACTS ?= --apply-loop-contracts
endif
# Silence makefile output (eg, long litani commands) unless VERBOSE is set.
ifndef VERBOSE
MAKEFLAGS := $(MAKEFLAGS) -s
endif
################################################################
################################################################
## Section II: This section defines the process of running a proof
##
## There should be no reason to edit anything below this line.
################################################################
# Paths
CBMC ?= cbmc
GOTO_ANALYZER ?= goto-analyzer
GOTO_CC ?= goto-cc
GOTO_INSTRUMENT ?= goto-instrument
CRANGLER ?= crangler
VIEWER ?= cbmc-viewer
MAKE_SOURCE ?= make-source
VIEWER2 ?= cbmc-viewer
CMAKE ?= cmake
GOTODIR ?= $(PROOFDIR)/gotos
LOGDIR ?= $(PROOFDIR)/logs
PROJECT ?= project
PROOF ?= proof
HARNESS_GOTO ?= $(GOTODIR)/$(HARNESS_FILE)
PROJECT_GOTO ?= $(GOTODIR)/$(PROJECT)
PROOF_GOTO ?= $(GOTODIR)/$(PROOF)
################################################################
# Useful macros for values that are hard to reference
SPACE :=$() $()
COMMA :=,
################################################################
# Set C compiler defines
CBMCFLAGS += --object-bits $(CBMC_OBJECT_BITS)
COMPILE_FLAGS += --object-bits $(CBMC_OBJECT_BITS)
DEFINES += -DCBMC=1
DEFINES += -DCBMC_OBJECT_BITS=$(CBMC_OBJECT_BITS)
DEFINES += -DCBMC_MAX_OBJECT_SIZE="(SIZE_MAX>>(CBMC_OBJECT_BITS+1))"
# CI currently assumes cbmc invocation has at most one --unwindset
ifdef UNWINDSET
ifneq ($(strip $(UNWINDSET)),"")
CBMC_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(UNWINDSET)))
endif
endif
ifdef EARLY_UNWINDSET
ifneq ($(strip $(EARLY_UNWINDSET)),"")
CBMC_EARLY_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(EARLY_UNWINDSET)))
endif
endif
CBMC_REMOVE_FUNCTION_BODY := $(patsubst %,--remove-function-body %, $(REMOVE_FUNCTION_BODY))
CBMC_RESTRICT_FUNCTION_POINTER := $(patsubst %,--restrict-function-pointer %, $(RESTRICT_FUNCTION_POINTER))
################################################################
# Targets for rewriting source files with crangler
# Construct crangler configuration files
#
# REWRITTEN_SOURCES is a list of crangler output files source.i.
# This target assumes that for each source.i
# * source.i_SOURCE is the path to a source file,
# * source.i_FUNCTIONS is a list of functions (may be empty)
# * source.i_OBJECTS is a list of variables (may be empty)
# This target constructs the crangler configuration file source.i.json
# of the form
# {
# "sources": [ "/proj/code.c" ],
# "includes": [ "/proj/include" ],
# "defines": [ "VAR=1" ],
# "functions": [ {"function_name": ["remove static"]} ],
# "objects": [ {"variable_name": ["remove static"]} ],
# "output": "source.i"
# }
# to remove the static attribute from function_name and variable_name
# in the source file source.c and write the result to source.i.
#
# This target assumes that filenames include no spaces and that
# the INCLUDES and DEFINES variables include no spaces after -I
# and -D. For example, use "-DVAR=1" and not "-D VAR=1".
#
# Define *_SOURCE, *_FUNCTIONS, and *_OBJECTS in the proof Makefile.
# The string source.i is usually an absolute path $(PROOFDIR)/code.i
# to a file in the proof directory that contains the proof Makefile.
# The proof Makefile usually includes the definitions
# $(PROOFDIR)/code.i_SOURCE = /proj/code.c
# $(PROOFDIR)/code.i_FUNCTIONS = function_name
# $(PROOFDIR)/code.i_OBJECTS = variable_name
# Because these definitions refer to PROOFDIR that is defined in this
# Makefile.common, these definitions must appear after the inclusion
# of Makefile.common in the proof Makefile.
#
$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs).json: $($(rs)_SOURCE)))
$(foreach rs,$(REWRITTEN_SOURCES),$(rs).json):
echo '{'\
'"sources": ['\
'"$($(@:.json=)_SOURCE)"'\
'],'\
'"includes": ['\
'$(subst $(SPACE),$(COMMA),$(patsubst -I%,"%",$(strip $(INCLUDES))))' \
'],'\
'"defines": ['\
'$(subst $(SPACE),$(COMMA),$(patsubst -D%,"%",$(subst ",\",$(strip $(DEFINES)))))' \
'],'\
'"functions": ['\
'{'\
'$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_FUNCTIONS))))' \
'}'\
'],'\
'"objects": ['\
'{'\
'$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_OBJECTS))))' \
'}'\
'],'\
'"output": "$(@:.json=)"'\
'}' > $@
# Rewrite source files with crangler
#
$(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs): $(rs).json))
$(REWRITTEN_SOURCES):
$(LITANI) add-job \
--command \
'$(CRANGLER) $@.json' \
--inputs $($@_SOURCE) \
--outputs $@ \
--stdout-file $(LOGDIR)/crangler-$(subst /,_,$(subst .,_,$@))-log.txt \
--interleave-stdout-stderr \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): removing static"
################################################################
# Build targets that make the relevant .goto files
# Compile project sources
$(PROJECT_GOTO)1.goto: $(PROJECT_SOURCES) $(REWRITTEN_SOURCES)
$(LITANI) add-job \
--command \
'$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/project_sources-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): building project binary"
# Compile proof sources
$(PROOF_GOTO)1.goto: $(PROOF_SOURCES)
$(LITANI) add-job \
--command \
'$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/proof_sources-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): building proof binary"
# Remove function bodies from project sources
$(PROJECT_GOTO)2.goto: $(PROJECT_GOTO)1.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_REMOVE_FUNCTION_BODY) $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/remove_function_body-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): removing function bodies from project sources"
# Link project and proof sources into the proof harness
$(HARNESS_GOTO)1.goto: $(PROOF_GOTO)1.goto $(PROJECT_GOTO)2.goto
$(LITANI) add-job \
--command '$(GOTO_CC) $(CBMC_VERBOSITY) --function $(HARNESS_ENTRY) $^ $(LINK_FLAGS) -o $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/link_proof_project-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): linking project to proof"
# Restrict function pointers
$(HARNESS_GOTO)2.goto: $(HARNESS_GOTO)1.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_RESTRICT_FUNCTION_POINTER) $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/restrict_function_pointer-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): restricting function pointers in project sources"
# Fill static variable with unconstrained values
$(HARNESS_GOTO)3.goto: $(HARNESS_GOTO)2.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(NONDET_STATIC) $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/nondet_static-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): setting static variables to nondet"
# Omit unused functions (sharpens coverage calculations)
$(HARNESS_GOTO)4.goto: $(HARNESS_GOTO)3.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --drop-unused-functions $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/drop_unused_functions-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): dropping unused functions"
# Omit initialization of unused global variables (reduces problem size)
$(HARNESS_GOTO)5.goto: $(HARNESS_GOTO)4.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --slice-global-inits $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/slice_global_inits-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): slicing global initializations"
# Replace function calls with function contracts
# This must be done before enforcing function contracts,
# since contract enforcement inlines all function calls.
$(HARNESS_GOTO)6.goto: $(HARNESS_GOTO)5.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_USE_FUNCTION_CONTRACTS) $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/use_function_contracts-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): replacing function calls with function contracts"
# Unwind loops for loop and function contracts
$(HARNESS_GOTO)7.goto: $(HARNESS_GOTO)6.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_EARLY_UNWINDSET) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/unwind_loops-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): unwinding loops"
# Apply loop contracts
$(HARNESS_GOTO)8.goto: $(HARNESS_GOTO)7.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_APPLY_LOOP_CONTRACTS) $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/apply_loop_contracts-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): applying loop contracts"
# Check function contracts
$(HARNESS_GOTO)9.goto: $(HARNESS_GOTO)8.goto
$(LITANI) add-job \
--command \
'$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_CHECK_FUNCTION_CONTRACTS) $^ $@' \
--inputs $^ \
--outputs $@ \
--stdout-file $(LOGDIR)/check_function_contracts-log.txt \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): checking function contracts"
# Final name for proof harness
$(HARNESS_GOTO).goto: $(HARNESS_GOTO)9.goto
$(LITANI) add-job \
--command 'cp $< $@' \
--inputs $^ \
--outputs $@ \
--pipeline-name "$(PROOF_UID)" \
--ci-stage build \
--description "$(PROOF_UID): copying final goto-binary"
################################################################
# Targets to run the analysis commands
$(LOGDIR)/result.txt: $(HARNESS_GOTO).goto
$(LITANI) add-job \
$(POOL) \
--command \
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace $<' \
--inputs $^ \
--outputs $@ \
--ci-stage test \
--stdout-file $@ \
$(MEMORY_PROFILING) \
--ignore-returns 10 \
--timeout $(CBMC_TIMEOUT) \
--pipeline-name "$(PROOF_UID)" \
--tags "stats-group:safety checks" \
--stderr-file $(LOGDIR)/result-err-log.txt \
--description "$(PROOF_UID): checking safety properties"
$(LOGDIR)/result.xml: $(HARNESS_GOTO).goto
$(LITANI) add-job \
$(POOL) \
--command \
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace --xml-ui $<' \
--inputs $^ \
--outputs $@ \
--ci-stage test \
--stdout-file $@ \
$(MEMORY_PROFILING) \
--ignore-returns 10 \
--timeout $(CBMC_TIMEOUT) \
--pipeline-name "$(PROOF_UID)" \
--tags "stats-group:safety checks" \
--stderr-file $(LOGDIR)/result-err-log.txt \
--description "$(PROOF_UID): checking safety properties"
$(LOGDIR)/property.xml: $(HARNESS_GOTO).goto
$(LITANI) add-job \
--command \
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --show-properties --xml-ui $<' \
--inputs $^ \
--outputs $@ \
--ci-stage test \
--stdout-file $@ \
--ignore-returns 10 \
--pipeline-name "$(PROOF_UID)" \
--stderr-file $(LOGDIR)/property-err-log.txt \
--description "$(PROOF_UID): printing safety properties"
$(LOGDIR)/coverage.xml: $(HARNESS_GOTO).goto
$(LITANI) add-job \
$(POOL) \
--command \
'$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(COVERFLAGS) --cover location --xml-ui $<' \
--inputs $^ \
--outputs $@ \
--ci-stage test \
--stdout-file $@ \
$(MEMORY_PROFILING) \
--ignore-returns 10 \
--timeout $(CBMC_TIMEOUT) \
--pipeline-name "$(PROOF_UID)" \
--tags "stats-group:coverage computation" \
--stderr-file $(LOGDIR)/coverage-err-log.txt \
--description "$(PROOF_UID): calculating coverage"
define VIEWER_CMD
$(VIEWER) \
--result $(LOGDIR)/result.txt \
--block $(LOGDIR)/coverage.xml \
--property $(LOGDIR)/property.xml \
--srcdir $(SRCDIR) \
--goto $(HARNESS_GOTO).goto \
--htmldir $(PROOFDIR)/html
endef
export VIEWER_CMD
$(PROOFDIR)/html: $(LOGDIR)/result.txt $(LOGDIR)/property.xml $(LOGDIR)/coverage.xml
$(LITANI) add-job \
--command "$$VIEWER_CMD" \
--inputs $^ \
--outputs $(PROOFDIR)/html \
--pipeline-name "$(PROOF_UID)" \
--ci-stage report \
--stdout-file $(LOGDIR)/viewer-log.txt \
--description "$(PROOF_UID): generating report"
# Caution: run make-source before running property and coverage checking
# The current make-source script removes the goto binary
$(LOGDIR)/source.json:
mkdir -p $(dir $@)
$(RM) -r $(GOTODIR)
$(MAKE_SOURCE) --srcdir $(SRCDIR) --wkdir $(PROOFDIR) > $@
$(RM) -r $(GOTODIR)
define VIEWER2_CMD
$(VIEWER2) \
--result $(LOGDIR)/result.xml \
--coverage $(LOGDIR)/coverage.xml \
--property $(LOGDIR)/property.xml \
--srcdir $(SRCDIR) \
--goto $(HARNESS_GOTO).goto \
--reportdir $(PROOFDIR)/report \
--config $(PROOFDIR)/cbmc-viewer.json
endef
export VIEWER2_CMD
# Omit logs/source.json from report generation until make-sources
# works correctly with Makefiles that invoke the compiler with
# mutliple source files at once.
$(PROOFDIR)/report: $(LOGDIR)/result.xml $(LOGDIR)/property.xml $(LOGDIR)/coverage.xml
$(LITANI) add-job \
--command "$$VIEWER2_CMD" \
--inputs $^ \
--outputs $(PROOFDIR)/report \
--pipeline-name "$(PROOF_UID)" \
--stdout-file $(LOGDIR)/viewer-log.txt \
--ci-stage report \
--description "$(PROOF_UID): generating report"
litani-path:
@echo $(LITANI)
# ##############################################################
# Phony Rules
#
# These rules provide a convenient way to run a single proof up to a
# certain stage. Users can browse into a proof directory and run
# "make -Bj 3 report" to generate a report for just that proof, or
# "make goto" to build the goto binary. Under the hood, this runs litani
# for just that proof.
_goto: $(HARNESS_GOTO).goto
goto:
@ echo Running 'litani init'
$(LITANI) init --project $(PROJECT_NAME)
@ echo Running 'litani add-job'
$(MAKE) -B _goto
@ echo Running 'litani build'
$(LITANI) run-build
_result: $(LOGDIR)/result.txt
result:
@ echo Running 'litani init'
$(LITANI) init --project $(PROJECT_NAME)
@ echo Running 'litani add-job'
$(MAKE) -B _result
@ echo Running 'litani build'
$(LITANI) run-build
_property: $(LOGDIR)/property.xml
property:
@ echo Running 'litani init'
$(LITANI) init --project $(PROJECT_NAME)
@ echo Running 'litani add-job'
$(MAKE) -B _property
@ echo Running 'litani build'
$(LITANI) run-build
_coverage: $(LOGDIR)/coverage.xml
coverage:
@ echo Running 'litani init'
$(LITANI) init --project $(PROJECT_NAME)
@ echo Running 'litani add-job'
$(MAKE) -B _coverage
@ echo Running 'litani build'
$(LITANI) run-build
# Choose the invocation of cbmc-viewer depending on which version of
# cbmc-viewer is installed. The --version flag is not implemented in
# version 1 --- it is an "unrecognized argument" --- but it is
# implemented in version 2.
_report1: $(PROOFDIR)/html
_report2: $(PROOFDIR)/report
_report:
(cbmc-viewer --version 2>&1 | grep "unrecognized argument" > /dev/null) && \
$(MAKE) -B _report1 || $(MAKE) -B _report2
report report1 report2:
@ echo Running 'litani init'
$(LITANI) init --project $(PROJECT_NAME)
@ echo Running 'litani add-job'
$(MAKE) -B _report
@ echo Running 'litani build'
$(LITANI) run-build
################################################################
# Targets to clean up after ourselves
clean:
-$(RM) $(DEPENDENT_GOTOS)
-$(RM) TAGS*
-$(RM) *~ \#*
-$(RM) $(REWRITTEN_SOURCES) $(foreach rs,$(REWRITTEN_SOURCES),$(rs).json)
veryclean: clean
-$(RM) -r html report
-$(RM) -r $(LOGDIR) $(GOTODIR)
.PHONY: \
_coverage \
_goto \
_property \
_report \
_report2 \
_result \
clean \
coverage \
goto \
litani-path \
property \
report \
report2 \
result \
setup_dependencies \
testdeps \
veryclean \
#
################################################################
# Rule for generating cbmc-batch.yaml, used by the CI at
# https://github.com/awslabs/aws-batch-cbmc/
JOB_OS ?= ubuntu16
JOB_MEMORY ?= 32000
# Proofs that are expected to fail should set EXPECTED to
# "FAILED" in their Makefile. Values other than SUCCESSFUL
# or FAILED will cause a CI error.
EXPECTED ?= SUCCESSFUL
define yaml_encode_options
"$(shell echo $(1) | sed 's/ ,/ /g' | sed 's/ /;/g')"
endef
CI_FLAGS = $(CBMCFLAGS) $(CHECKFLAGS) $(COVERFLAGS)
cbmc-batch.yaml:
@$(RM) $@
@echo 'build_memory: $(JOB_MEMORY)' > $@
@echo 'cbmcflags: $(strip $(call yaml_encode_options,$(CI_FLAGS)))' >> $@
@echo 'coverage_memory: $(JOB_MEMORY)' >> $@
@echo 'expected: $(EXPECTED)' >> $@
@echo 'goto: $(HARNESS_GOTO).goto' >> $@
@echo 'jobos: $(JOB_OS)' >> $@
@echo 'property_memory: $(JOB_MEMORY)' >> $@
@echo 'report_memory: $(JOB_MEMORY)' >> $@
.PHONY: cbmc-batch.yaml
################################################################
# Run "make echo-proof-uid" to print the proof ID of a proof. This can be
# used by scripts to ensure that every proof has an ID, that there are
# no duplicates, etc.
.PHONY: echo-proof-uid
echo-proof-uid:
@echo $(PROOF_UID)
.PHONY: echo-project-name
echo-project-name:
@echo $(PROJECT_NAME)
################################################################
# Project-specific targets requiring values defined above
sinclude $(PROOF_ROOT)/Makefile-project-targets
# CI-specific targets to drive cbmc in CI
sinclude $(PROOF_ROOT)/Makefile-project-testing
################################################################

View File

@ -0,0 +1,27 @@
CBMC proofs
===========
This directory contains the CBMC proofs. Each proof is in its own
directory.
This directory includes four Makefiles.
One Makefile describes the basic workflow for building and running proofs:
* Makefile.common:
* make: builds the goto binary, does the cbmc property checking
and coverage checking, and builds the final report.
* make goto: builds the goto binary
* make result: does cbmc property checking
* make coverage: does cbmc coverage checking
* make report: builds the final report
Three included Makefiles describe project-specific settings and can override
definitions in Makefile.common:
* Makefile-project-defines: definitions like compiler flags
required to build the goto binaries, and definitions to override
definitions in Makefile.common.
* Makefile-project-targets: other make targets needed for the project
* Makefile-project-testing: other definitions and targets needed for
unit testing or continuous integration.

View File

@ -0,0 +1,31 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
HARNESS_ENTRY = harness
HARNESS_FILE = SigV4_AwsIotDateToIso8601_harness
# This should be a unique identifier for this proof, and will appear on the
# Litani dashboard. It can be human-readable and contain spaces if you wish.
PROOF_UID = SigV4_AwsIotDateToIso8601
DEFINES += -DSIGV4_DO_NOT_USE_CUSTOM_CONFIG=1
INCLUDES +=
MONTH_ASCII_LEN=3
ISO_YEAR_LEN=5
MONTHS_IN_YEAR=12
FORMAT_RFC_5322_LEN=32
REMOVE_FUNCTION_BODY +=
UNWINDSET += parseDate.0:$(FORMAT_RFC_5322_LEN)
UNWINDSET += scanValue.0:$(ISO_YEAR_LEN)
UNWINDSET += intToAscii.0:$(ISO_YEAR_LEN)
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/sigv4_stubs.c
include ../Makefile-json.common
# Substitution command to pass to sed for patching sigv4.c. The
# characters " and # must be escaped with backslash.
SIGV4_SED_EXPR = 1s/^/\#include \"sigv4_stubs.h\" /; s/^static //; s/SigV4Status_t scanValue\b/&_/

View File

@ -0,0 +1,20 @@
SigV4_AwsIotDateToIso8601 proof
==============
This directory contains a memory safety proof for SigV4_AwsIotDateToIso8601.
To run the proof.
-------------
* Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer`
to your path.
* Run `make`.
* Open html/index.html in a web browser.
To use [`arpa`](https://github.com/awslabs/aws-proof-build-assistant) to simplify writing Makefiles.
-------------
* Run `make arpa` to generate a Makefile.arpa that contains relevant build information for the proof.
* Use Makefile.arpa as the starting point for your proof Makefile by:
1. Modifying Makefile.arpa (if required).
2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`).

View File

@ -0,0 +1,52 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file SigV4_AwsIotDateToIso8601_harness.c
* @brief Implements the proof harness for SigV4_AwsIotDateToIso8601 function.
*/
#include "stdlib.h"
#include "sigv4.h"
void harness()
{
char * pInputDate;
size_t dateLen;
char * pDateISO8601;
size_t dateISO8601Len;
SigV4Status_t status;
__CPROVER_assume( dateLen == SIGV4_EXPECTED_LEN_RFC_3339 || dateLen == SIGV4_EXPECTED_LEN_RFC_5322 || dateLen == 0 );
pInputDate = malloc( dateLen );
__CPROVER_assume( dateISO8601Len < CBMC_MAX_OBJECT_SIZE );
pDateISO8601 = malloc( dateISO8601Len );
status = SigV4_AwsIotDateToIso8601( pInputDate, dateLen, pDateISO8601, dateISO8601Len );
__CPROVER_assert( status == SigV4InvalidParameter || status == SigV4Success || status == SigV4ISOFormattingError, "This is not a valid SigV4 return status" );
}

View File

@ -0,0 +1 @@
# This file marks this directory as containing a CBMC proof.

View File

@ -0,0 +1,7 @@
{ "expected-missing-functions":
[
],
"proof-name": "SigV4_AwsIotDateToIso8601",
"proof-root": "test/cbmc/proofs"
}

View File

@ -0,0 +1,64 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
HARNESS_ENTRY = harness
HARNESS_FILE = SigV4_GenerateHTTPAuthorization_harness
# This should be a unique identifier for this proof, and will appear on the
# Litani dashboard. It can be human-readable and contain spaces if you wish.
PROOF_UID = SigV4_GenerateHTTPAuthorization
# Define constants so as to limit the running time of the proofs.
# Note that these constants are also deliberately chosen so as to attain
# coverage for the SigV4InsufficientMemory cases.
# For the constants below,
# SIGV4_PROCESSING_BUFFER_LENGTH is set specifically to 60.
# It may be easier to attain coverage if the processing buffer is instead
# provided by the user as the length can be variable.
# However, since the length of the processing buffer is fixed,
# these constants must also be fixed in order to match whatever
# SIGV4_PROCESSING_BUFFER_LENGTH is set to in sigv4_config.h.
MAX_QUERY_LEN=6
MAX_HEADERS_LEN=6
MAX_URI_LEN=3
MAX_REQUEST_LEN=16
S3_SERVICE_LEN=2
MAX_REGION_LEN=30
MAX_SERVICE_LEN=30
MAX_ALGORITHM_LEN=30
MAX_HASH_DIGEST_LEN=16
MAX_HASH_BLOCK_LEN=17
# This is the actual maximum length of an AWS access key ID
MAX_ACCESS_KEY_ID_LEN=128
DEFINES += -DMAX_QUERY_LEN=$(MAX_QUERY_LEN)
DEFINES += -DMAX_HEADERS_LEN=$(MAX_HEADERS_LEN)
DEFINES += -DMAX_URI_LEN=$(MAX_URI_LEN)
DEFINES += -DMAX_HASH_DIGEST_LEN=$(MAX_HASH_DIGEST_LEN)
DEFINES += -DMAX_HASH_BLOCK_LEN=$(MAX_HASH_BLOCK_LEN)
DEFINES += -DMAX_REGION_LEN=$(MAX_REGION_LEN)
DEFINES += -DMAX_SERVICE_LEN=$(MAX_SERVICE_LEN)
DEFINES += -DMAX_ALGORITHM_LEN=$(MAX_ALGORITHM_LEN)
DEFINES += -DMAX_ACCESS_KEY_ID_LEN=$(MAX_ACCESS_KEY_ID_LEN)
INCLUDES +=
REMOVE_FUNCTION_BODY += memcpy
REMOVE_FUNCTION_BODY += memmove
UNWINDSET += setQueryStringFieldsAndValues.0:$(MAX_QUERY_LEN)
UNWINDSET += parseHeaderKeyValueEntries.0:$(MAX_HEADERS_LEN)
UNWINDSET += lowercaseHexEncode.0:$(MAX_HASH_DIGEST_LEN)
UNWINDSET += hmacIntermediate.0:$(MAX_HASH_BLOCK_LEN)
UNWINDSET += hmacFinal.0:$(MAX_HASH_BLOCK_LEN)
UNWINDSET += strncmp.0:$(S3_SERVICE_LEN)
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/hash_stubs.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/memcpy.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/memmove.c
PROOF_SOURCES += $(SRCDIR)/test/cbmc/stubs/sigv4_stubs.c
include ../Makefile-json.common
# Substitution command to pass to sed for patching sigv4.c. The
# characters " and # must be escaped with backslash.
SIGV4_SED_EXPR = 1s/^/\#include \"sigv4_stubs.h\" /; s/^static //; s/SigV4Status_t (scanValue|encodeURI|generateCanonicalQuery|generateCanonicalAndSignedHeaders|copyHeaderStringToCanonicalBuffer)\b/&_/

View File

@ -0,0 +1,20 @@
SigV4_GenerateHTTPAuthorization proof
==============
This directory contains a memory safety proof for SigV4_GenerateHTTPAuthorization.
To run the proof.
-------------
* Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer`
to your path.
* Run `make`.
* Open html/index.html in a web browser.
To use [`arpa`](https://github.com/awslabs/aws-proof-build-assistant) to simplify writing Makefiles.
-------------
* Run `make arpa` to generate a Makefile.arpa that contains relevant build information for the proof.
* Use Makefile.arpa as the starting point for your proof Makefile by:
1. Modifying Makefile.arpa (if required).
2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`).

View File

@ -0,0 +1,131 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file SigV4_GenerateHTTPAuthorization_harness.c
* @brief Implements the proof harness for the SigV4_GenerateHTTPAuthorization function.
*/
/* Include paths for public enums, structures, and macros. */
#include "stdlib.h"
#include "sigv4.h"
#include "sigv4_internal.h"
#include "hash_stubs.h"
void harness()
{
SigV4Parameters_t * pSigV4Params;
SigV4HttpParameters_t * pHttpParams;
SigV4CryptoInterface_t * pCryptoInterface;
SigV4Credentials_t * pCredentials;
char * pAuthBuf;
size_t * authBufLen;
char * pSignature;
size_t signatureLen;
SigV4Status_t status;
pHttpParams = malloc( sizeof( SigV4HttpParameters_t ) );
pSigV4Params = malloc( sizeof( SigV4Parameters_t ) );
pCryptoInterface = malloc( sizeof( SigV4CryptoInterface_t ) );
pCredentials = malloc( sizeof( SigV4Credentials_t ) );
/* This property applies to all hash functions. */
if( pCryptoInterface != NULL )
{
__CPROVER_assume( SIGV4_HMAC_SIGNING_KEY_PREFIX_LEN < pCryptoInterface->hashBlockLen && pCryptoInterface->hashBlockLen <= MAX_HASH_BLOCK_LEN );
__CPROVER_assume( 0U < pCryptoInterface->hashDigestLen && pCryptoInterface->hashDigestLen <= MAX_HASH_DIGEST_LEN );
__CPROVER_assume( pCryptoInterface->hashDigestLen <= pCryptoInterface->hashBlockLen );
pCryptoInterface->hashInit = nondet_bool() ? NULL : HashInitStub;
pCryptoInterface->hashUpdate = nondet_bool() ? NULL : HashUpdateStub;
pCryptoInterface->hashFinal = nondet_bool() ? NULL : HashFinalStub;
}
if( pCredentials != NULL )
{
/* Make size assumptions for string-like types. */
__CPROVER_assume( pCredentials->accessKeyIdLen <= MAX_ACCESS_KEY_ID_LEN );
__CPROVER_assume( pCredentials->secretAccessKeyLen < CBMC_MAX_OBJECT_SIZE );
pCredentials->pAccessKeyId = malloc( pCredentials->accessKeyIdLen );
pCredentials->pSecretAccessKey = malloc( pCredentials->secretAccessKeyLen );
}
if( pHttpParams != NULL )
{
/* Make size assumptions for string-like types. */
__CPROVER_assume( pHttpParams->payloadLen < CBMC_MAX_OBJECT_SIZE );
__CPROVER_assume( pHttpParams->httpMethodLen < CBMC_MAX_OBJECT_SIZE );
__CPROVER_assume( pHttpParams->pathLen < MAX_URI_LEN );
__CPROVER_assume( pHttpParams->queryLen < MAX_QUERY_LEN );
__CPROVER_assume( pHttpParams->headersLen < MAX_HEADERS_LEN );
pHttpParams->pPayload = malloc( pHttpParams->payloadLen );
pHttpParams->pHttpMethod = malloc( pHttpParams->httpMethodLen );
pHttpParams->pPath = malloc( pHttpParams->pathLen );
pHttpParams->pQuery = malloc( pHttpParams->queryLen );
pHttpParams->pHeaders = malloc( pHttpParams->headersLen );
}
if( pSigV4Params != NULL )
{
/* Make size assumptions for string-like types. */
__CPROVER_assume( pSigV4Params->regionLen < MAX_REGION_LEN );
__CPROVER_assume( pSigV4Params->serviceLen < MAX_SERVICE_LEN );
__CPROVER_assume( pSigV4Params->algorithmLen < MAX_ALGORITHM_LEN );
pSigV4Params->pRegion = malloc( pSigV4Params->regionLen );
pSigV4Params->pService = malloc( pSigV4Params->serviceLen );
pSigV4Params->pAlgorithm = malloc( pSigV4Params->algorithmLen );
/* The ISO date has a fixed length. */
pSigV4Params->pDateIso8601 = malloc( SIGV4_ISO_STRING_LEN );
/* Set other structs within SigV4Parameters_t. */
pSigV4Params->pCredentials = pCredentials;
pSigV4Params->pCryptoInterface = pCryptoInterface;
pSigV4Params->pHttpParameters = pHttpParams;
}
authBufLen = malloc( sizeof( size_t ) );
if( authBufLen != NULL )
{
__CPROVER_assume( *authBufLen < CBMC_MAX_OBJECT_SIZE );
pAuthBuf = malloc( *authBufLen );
}
status = SigV4_GenerateHTTPAuthorization( pSigV4Params,
pAuthBuf,
authBufLen,
nondet_bool() ? NULL : &pSignature,
nondet_bool() ? NULL : &signatureLen );
__CPROVER_assert( status == SigV4InvalidParameter || status == SigV4Success || status == SigV4HashError || status == SigV4InsufficientMemory || status == SigV4MaxHeaderPairCountExceeded || status == SigV4MaxQueryPairCountExceeded, "This is not a valid SigV4 return status" );
if( status == SigV4Success )
{
/* The signature must start at a location within pAuthBuf and
* should not end past the length of pAuthBuf. */
__CPROVER_assert( pAuthBuf <= pSignature,
"Signature does not start at a location within pAuthBuf." );
__CPROVER_assert( pSignature + signatureLen <= pAuthBuf + *authBufLen,
"Signature ends past the length of pAuthBuf." );
}
}

View File

@ -0,0 +1 @@
# This file marks this directory as containing a CBMC proof.

View File

@ -0,0 +1,7 @@
{ "expected-missing-functions":
[
],
"proof-name": "SigV4_GenerateHTTPAuthorization",
"proof-root": "test/cbmc/proofs"
}

View File

@ -0,0 +1,37 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
HARNESS_ENTRY = harness
HARNESS_FILE = copyHeaderStringToCanonicalBuffer_harness
# This should be a unique identifier for this proof, and will appear on the
# Litani dashboard. It can be human-readable and contain spaces if you wish.
PROOF_UID = copyHeaderStringToCanonicalBuffer
# This value was experimentally chosen to provide 100% coverage
# without tripping unwinding assertions and without exhausting memory.
CBMC_MAX_BUFSIZE=10
MAX_HASH_BLOCK_LEN=17
MAX_HASH_DIGEST_LEN=16
DEFINES += -DMAX_HASH_BLOCK_LEN=$(MAX_HASH_BLOCK_LEN)
DEFINES += -DCBMC_MAX_BUFSIZE=$(CBMC_MAX_BUFSIZE)
DEFINES += -DMAX_HASH_DIGEST_LEN=$(MAX_HASH_DIGEST_LEN)
INCLUDES +=
REMOVE_FUNCTION_BODY +=
UNWINDSET +=copyHeaderStringToCanonicalBuffer.0:$(CBMC_MAX_BUFSIZE)
PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
# If this proof is found to consume huge amounts of RAM, you can set the
# EXPENSIVE variable. With new enough versions of the proof tools, this will
# restrict the number of EXPENSIVE CBMC jobs running at once. See the
# documentation in Makefile.common under the "Job Pools" heading for details.
# EXPENSIVE = true
include ../Makefile-json.common
# Substitution command to pass to sed for patching sigv4.c. The
# characters " and # must be escaped with backslash.
SIGV4_SED_EXPR = s/^static //

View File

@ -0,0 +1,12 @@
copyHeaderStringToCanonicalBuffer proof
==============
This directory contains a memory safety proof for copyHeaderStringToCanonicalBuffer.
To run the proof.
-------------
* Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer`
to your path.
* Run `make`.
* Open html/index.html in a web browser.

View File

@ -0,0 +1 @@
# This file marks this directory as containing a CBMC proof.

View File

@ -0,0 +1,7 @@
{ "expected-missing-functions":
[
],
"proof-name": "copyHeaderStringToCanonicalBuffer",
"proof-root": "test/cbmc/proofs"
}

View File

@ -0,0 +1,62 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file copyHeaderStringToCanonicalBuffer_harness.c
* @brief Implements the proof harness for copyHeaderStringToCanonicalBuffer function.
*/
#include "stdlib.h"
#include "sigv4_annex.h"
void harness()
{
const char * pData;
size_t dataLen;
uint32_t flags;
char separator;
CanonicalContext_t * canonicalRequest;
SigV4Status_t sigv4Status;
canonicalRequest = malloc( sizeof( CanonicalContext_t ) );
__CPROVER_assume( canonicalRequest != NULL );
/* The data to be written is assumed to start at a location within the processing
* buffer and should not end past the length of the processing buffer. */
size_t bytesConsumed;
__CPROVER_assume( canonicalRequest->bufRemaining < SIGV4_PROCESSING_BUFFER_LENGTH );
bytesConsumed = SIGV4_PROCESSING_BUFFER_LENGTH - canonicalRequest->bufRemaining;
__CPROVER_assume( dataLen > 0U && dataLen < CBMC_MAX_BUFSIZE );
canonicalRequest->pBufCur = ( char * ) canonicalRequest->pBufProcessing + bytesConsumed;
pData = malloc( dataLen );
__CPROVER_assume( pData != NULL );
sigv4Status = copyHeaderStringToCanonicalBuffer( pData, dataLen, flags, separator, canonicalRequest );
__CPROVER_assert( ( sigv4Status == SigV4InvalidParameter || sigv4Status == SigV4Success || sigv4Status == SigV4InsufficientMemory ), "This is not a valid SIGV4 Status." );
}

View File

@ -0,0 +1,92 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
import json
import logging
def _get_max_length_per_column_list(data):
ret = [len(item) + 1 for item in data[0]]
for row in data[1:]:
for idx, item in enumerate(row):
ret[idx] = max(ret[idx], len(item) + 1)
return ret
def _get_table_header_separator(max_length_per_column_list):
line_sep = ""
for max_length_of_word_in_col in max_length_per_column_list:
line_sep += "|" + "-" * (max_length_of_word_in_col + 1)
line_sep += "|\n"
return line_sep
def _get_entries(max_length_per_column_list, row_data):
entries = []
for row in row_data:
entry = ""
for idx, word in enumerate(row):
max_length_of_word_in_col = max_length_per_column_list[idx]
space_formatted_word = (max_length_of_word_in_col - len(word)) * " "
entry += "| " + word + space_formatted_word
entry += "|\n"
entries.append(entry)
return entries
def _get_rendered_table(data):
table = []
max_length_per_column_list = _get_max_length_per_column_list(data)
entries = _get_entries(max_length_per_column_list, data)
for idx, entry in enumerate(entries):
if idx == 1:
line_sep = _get_table_header_separator(max_length_per_column_list)
table.append(line_sep)
table.append(entry)
table.append("\n")
return "".join(table)
def _get_status_and_proof_summaries(run_dict):
"""Parse a dict representing a Litani run and create lists summarizing the
proof results.
Parameters
----------
run_dict
A dictionary representing a Litani run.
Returns
-------
A list of 2 lists.
The first sub-list maps a status to the number of proofs with that status.
The second sub-list maps each proof to its status.
"""
count_statuses = {}
proofs = [["Proof", "Status"]]
for proof_pipeline in run_dict["pipelines"]:
status_pretty_name = proof_pipeline["status"].title().replace("_", " ")
try:
count_statuses[status_pretty_name] += 1
except KeyError:
count_statuses[status_pretty_name] = 1
proof = proof_pipeline["name"]
proofs.append([proof, status_pretty_name])
statuses = [["Status", "Count"]]
for status, count in count_statuses.items():
statuses.append([status, str(count)])
return [statuses, proofs]
def print_proof_results(out_file):
"""
Print 2 strings that summarize the proof results.
When printing, each string will render as a GitHub flavored Markdown table.
"""
try:
with open(out_file, encoding='utf-8') as run_json:
run_dict = json.load(run_json)
for summary in _get_status_and_proof_summaries(run_dict):
print(_get_rendered_table(summary))
except Exception as ex: # pylint: disable=broad-except
logging.critical("Could not print results. Exception: %s", str(ex))

View File

@ -0,0 +1,414 @@
#!/usr/bin/env python3
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
import argparse
import asyncio
import json
import logging
import math
import os
import pathlib
import re
import subprocess
import sys
import tempfile
from lib.summarize import print_proof_results
DESCRIPTION = "Configure and run all CBMC proofs in parallel"
# Keep the epilog hard-wrapped at 70 characters, as it gets printed
# verbatim in the terminal. 70 characters stops here --------------> |
EPILOG = """
This tool automates the process of running `make report` in each of
the CBMC proof directories. The tool calculates the dependency graph
of all tasks needed to build, run, and report on all the proofs, and
executes these tasks in parallel.
The tool is roughly equivalent to doing this:
litani init --project "my-cool-project";
find . -name cbmc-proof.txt | while read -r proof; do
pushd $(dirname ${proof});
# The `make _report` rule adds a single proof to litani
# without running it
make _report;
popd;
done
litani run-build;
except that it is much faster and provides some convenience options.
The CBMC CI runs this script with no arguments to build and run all
proofs in parallel. The value of "my-cool-project" is taken from the
PROJECT_NAME variable in Makefile-project-defines.
The --no-standalone argument omits the `litani init` and `litani
run-build`; use it when you want to add additional proof jobs, not
just the CBMC ones. In that case, you would run `litani init`
yourself; then run `run-cbmc-proofs --no-standalone`; add any
additional jobs that you want to execute with `litani add-job`; and
finally run `litani run-build`.
The litani dashboard will be written under the `output` directory; the
cbmc-viewer reports remain in the `$PROOF_DIR/report` directory. The
HTML dashboard from the latest Litani run will always be symlinked to
`output/latest/html/index.html`, so you can keep that page open in
your browser and reload the page whenever you re-run this script.
"""
# 70 characters stops here ----------------------------------------> |
def get_project_name():
cmd = [
"make",
"--no-print-directory",
"-f", "Makefile.common",
"echo-project-name",
]
logging.debug(" ".join(cmd))
proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False)
if proc.returncode:
logging.critical("could not run make to determine project name")
sys.exit(1)
if not proc.stdout.strip():
logging.warning(
"project name has not been set; using generic name instead. "
"Set the PROJECT_NAME value in Makefile-project-defines to "
"remove this warning")
return "<PROJECT NAME HERE>"
return proc.stdout.strip()
def get_args():
pars = argparse.ArgumentParser(
description=DESCRIPTION, epilog=EPILOG,
formatter_class=argparse.RawDescriptionHelpFormatter)
for arg in [{
"flags": ["-j", "--parallel-jobs"],
"type": int,
"metavar": "N",
"help": "run at most N proof jobs in parallel",
}, {
"flags": ["--fail-on-proof-failure"],
"action": "store_true",
"help": "exit with return code `10' if any proof failed"
" (default: exit 0)",
}, {
"flags": ["--no-standalone"],
"action": "store_true",
"help": "only configure proofs: do not initialize nor run",
}, {
"flags": ["-p", "--proofs"],
"nargs": "+",
"metavar": "DIR",
"help": "only run proof in directory DIR (can pass more than one)",
}, {
"flags": ["--project-name"],
"metavar": "NAME",
"default": get_project_name(),
"help": "project name for report. Default: %(default)s",
}, {
"flags": ["--marker-file"],
"metavar": "FILE",
"default": "cbmc-proof.txt",
"help": (
"name of file that marks proof directories. Default: "
"%(default)s"),
}, {
"flags": ["--no-memory-profile"],
"action": "store_true",
"help": "disable memory profiling, even if Litani supports it"
}, {
"flags": ["--no-expensive-limit"],
"action": "store_true",
"help": "do not limit parallelism of 'EXPENSIVE' jobs",
}, {
"flags": ["--expensive-jobs-parallelism"],
"metavar": "N",
"default": 1,
"type": int,
"help": (
"how many proof jobs marked 'EXPENSIVE' to run in parallel. "
"Default: %(default)s"),
}, {
"flags": ["--verbose"],
"action": "store_true",
"help": "verbose output",
}, {
"flags": ["--debug"],
"action": "store_true",
"help": "debug output",
}, {
"flags": ["--summarize"],
"action": "store_true",
"help": "summarize proof results with two tables on stdout",
}, {
"flags": ["--version"],
"action": "version",
"version": "CBMC starter kit 2.5",
"help": "display version and exit"
}]:
flags = arg.pop("flags")
pars.add_argument(*flags, **arg)
return pars.parse_args()
def set_up_logging(verbose):
if verbose:
level = logging.DEBUG
else:
level = logging.WARNING
logging.basicConfig(
format="run-cbmc-proofs: %(message)s", level=level)
def task_pool_size():
ret = os.cpu_count()
if ret is None or ret < 3:
return 1
return ret - 2
def print_counter(counter):
# pylint: disable=consider-using-f-string
print("\rConfiguring CBMC proofs: "
"{complete:{width}} / {total:{width}}".format(**counter), end="", file=sys.stderr)
def get_proof_dirs(proof_root, proof_list, marker_file):
if proof_list is not None:
proofs_remaining = list(proof_list)
else:
proofs_remaining = []
for root, _, fyles in os.walk(proof_root):
proof_name = str(pathlib.Path(root).name)
if root != str(proof_root) and ".litani_cache_dir" in fyles:
pathlib.Path(f"{root}/.litani_cache_dir").unlink()
if proof_list and proof_name not in proof_list:
continue
if proof_list and proof_name in proofs_remaining:
proofs_remaining.remove(proof_name)
if marker_file in fyles:
yield root
if proofs_remaining:
logging.critical(
"The following proofs were not found: %s",
", ".join(proofs_remaining))
sys.exit(1)
def run_build(litani, jobs, fail_on_proof_failure, summarize):
cmd = [str(litani), "run-build"]
if jobs:
cmd.extend(["-j", str(jobs)])
if fail_on_proof_failure:
cmd.append("--fail-on-pipeline-failure")
if summarize:
out_file = pathlib.Path(tempfile.gettempdir(), "run.json").resolve()
cmd.extend(["--out-file", str(out_file)])
logging.debug(" ".join(cmd))
proc = subprocess.run(cmd, check=False)
if proc.returncode and not fail_on_proof_failure:
logging.critical("Failed to run litani run-build")
sys.exit(1)
if summarize:
print_proof_results(out_file)
out_file.unlink()
if proc.returncode:
logging.error("One or more proofs failed")
sys.exit(10)
def get_litani_path(proof_root):
cmd = [
"make",
"--no-print-directory",
f"PROOF_ROOT={proof_root}",
"-f", "Makefile.common",
"litani-path",
]
logging.debug(" ".join(cmd))
proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False)
if proc.returncode:
logging.critical("Could not determine path to litani")
sys.exit(1)
return proc.stdout.strip()
def get_litani_capabilities(litani_path):
cmd = [litani_path, "print-capabilities"]
proc = subprocess.run(
cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False)
if proc.returncode:
return []
try:
return json.loads(proc.stdout)
except RuntimeError:
logging.warning("Could not load litani capabilities: '%s'", proc.stdout)
return []
def check_uid_uniqueness(proof_dir, proof_uids):
with (pathlib.Path(proof_dir) / "Makefile").open() as handle:
for line in handle:
match = re.match(r"^PROOF_UID\s*=\s*(?P<uid>\w+)", line)
if not match:
continue
if match["uid"] not in proof_uids:
proof_uids[match["uid"]] = proof_dir
return
logging.critical(
"The Makefile in directory '%s' should have a different "
"PROOF_UID than the Makefile in directory '%s'",
proof_dir, proof_uids[match["uid"]])
sys.exit(1)
logging.critical(
"The Makefile in directory '%s' should contain a line like", proof_dir)
logging.critical("PROOF_UID = ...")
logging.critical("with a unique identifier for the proof.")
sys.exit(1)
def should_enable_memory_profiling(litani_caps, args):
if args.no_memory_profile:
return False
return "memory_profile" in litani_caps
def should_enable_pools(litani_caps, args):
if args.no_expensive_limit:
return False
return "pools" in litani_caps
async def configure_proof_dirs( # pylint: disable=too-many-arguments
queue, counter, proof_uids, enable_pools, enable_memory_profiling, debug):
while True:
print_counter(counter)
path = str(await queue.get())
check_uid_uniqueness(path, proof_uids)
pools = ["ENABLE_POOLS=true"] if enable_pools else []
profiling = [
"ENABLE_MEMORY_PROFILING=true"] if enable_memory_profiling else []
# Allow interactive tasks to preempt proof configuration
proc = await asyncio.create_subprocess_exec(
"nice", "-n", "15", "make", *pools,
*profiling, "-B", "_report", "" if debug else "--quiet", cwd=path,
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
logging.debug("returncode: %s", str(proc.returncode))
logging.debug("stdout:")
for line in stdout.decode().splitlines():
logging.debug(line)
logging.debug("stderr:")
for line in stderr.decode().splitlines():
logging.debug(line)
counter["fail" if proc.returncode else "pass"].append(path)
counter["complete"] += 1
print_counter(counter)
queue.task_done()
async def main(): # pylint: disable=too-many-locals
args = get_args()
set_up_logging(args.verbose)
proof_root = pathlib.Path(os.getcwd())
litani = get_litani_path(proof_root)
litani_caps = get_litani_capabilities(litani)
enable_pools = should_enable_pools(litani_caps, args)
init_pools = [
"--pools", f"expensive:{args.expensive_jobs_parallelism}"
] if enable_pools else []
if not args.no_standalone:
cmd = [
str(litani), "init", *init_pools, "--project", args.project_name,
"--no-print-out-dir",
]
if "output_directory_flags" in litani_caps:
out_prefix = proof_root / "output"
out_symlink = out_prefix / "latest"
out_index = out_symlink / "html" / "index.html"
cmd.extend([
"--output-prefix", str(out_prefix),
"--output-symlink", str(out_symlink),
])
print(
"\nFor your convenience, the output of this run will be symbolically linked to ",
out_index, "\n")
logging.debug(" ".join(cmd))
proc = subprocess.run(cmd, check=False)
if proc.returncode:
logging.critical("Failed to run litani init")
sys.exit(1)
proof_dirs = list(get_proof_dirs(
proof_root, args.proofs, args.marker_file))
if not proof_dirs:
logging.critical("No proof directories found")
sys.exit(1)
proof_queue = asyncio.Queue()
for proof_dir in proof_dirs:
proof_queue.put_nowait(proof_dir)
counter = {
"pass": [],
"fail": [],
"complete": 0,
"total": len(proof_dirs),
"width": int(math.log10(len(proof_dirs))) + 1
}
proof_uids = {}
tasks = []
enable_memory_profiling = should_enable_memory_profiling(litani_caps, args)
for _ in range(task_pool_size()):
task = asyncio.create_task(configure_proof_dirs(
proof_queue, counter, proof_uids, enable_pools,
enable_memory_profiling, args.debug))
tasks.append(task)
await proof_queue.join()
print_counter(counter)
print("", file=sys.stderr)
if counter["fail"]:
logging.critical(
"Failed to configure the following proofs:\n%s", "\n".join(
[str(f) for f in counter["fail"]]))
sys.exit(1)
if not args.no_standalone:
run_build(litani, args.parallel_jobs, args.fail_on_proof_failure, args.summarize)
if __name__ == "__main__":
asyncio.run(main())

View File

@ -0,0 +1,6 @@
CBMC proof source code
======================
This directory contains source code written for CBMC proofs. It is
common to write some code to model aspects of the system under test,
and this code goes here.

View File

@ -0,0 +1,6 @@
CBMC proof stubs
======================
This directory contains the stubs written for CBMC proofs. It is
common to stub out functionality like network send and receive methods
when writing a CBMC proof, and the code for these stubs goes here.

View File

@ -0,0 +1,57 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file hash_stubs.c
* @brief Declarations for stubs used in sigv4.c.
* Please see sigv4.c for documentation.
*/
/* Standard includes. */
#include "hash_stubs.h"
int32_t HashInitStub( void * pHashContext )
{
int32_t ret;
return ret;
}
int32_t HashUpdateStub( void * pHashContext,
const char * pInput,
size_t inputLen )
{
int32_t ret;
return ret;
}
int32_t HashFinalStub( void * pHashContext,
const char * pInput,
size_t inputLen )
{
int32_t ret;
return ret;
}

View File

@ -0,0 +1,62 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file memcpy.c
* @brief A stub for memcpy so that the proofs for functions that call memcpy
* run much faster.
*/
#include <string.h>
/* This is a clang macro not available on linux */
#ifndef __has_builtin
#define __has_builtin( x ) 0
#endif
#if __has_builtin( __builtin___memcpy_chk )
void * __builtin___memcpy_chk( void * dest,
const void * src,
size_t n,
size_t m )
{
/* Attempting to read or write 0 bytes will make __CPROVER_r/w_ok
* fail. However, per ANSI C specification, memcpy must be able
* to handle a copy length of zero. */
__CPROVER_assert( ( n == 0 ) || __CPROVER_w_ok( dest, n ), "write" );
__CPROVER_assert( ( n == 0 ) || __CPROVER_r_ok( src, n ), "read" );
return dest;
}
#else /* if __has_builtin( __builtin___memcpy_chk ) */
void * memcpy( void * dest,
const void * src,
size_t n )
{
/* Per ANSI C specification, memcpy must be able to handle a copy length
* of zero. */
__CPROVER_assert( ( n == 0 ) || __CPROVER_w_ok( dest, n ), "write" );
__CPROVER_assert( ( n == 0 ) || __CPROVER_r_ok( src, n ), "read" );
return dest;
}
#endif /* if __has_builtin( __builtin___memcpy_chk ) */

View File

@ -0,0 +1,60 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file memmove.c
* @brief A stub for memmove so that the proofs for functions that call
* memmove run much faster.
*/
#include <string.h>
/* This is a clang macro not available on linux */
#ifndef __has_builtin
#define __has_builtin( x ) 0
#endif
#if __has_builtin( __builtin___memmove_chk )
void * __builtin___memmove_chk( void * dest,
const void * src,
size_t n,
size_t m )
{
/* Attempting to read or write 0 bytes will make __CPROVER_r/w_ok
* fail. However, per ANSI C specification, memcpy must be able
* to handle a copy length of zero. */
__CPROVER_assert( ( n == 0 ) || __CPROVER_w_ok( dest, n ), "write" );
__CPROVER_assert( ( n == 0 ) || __CPROVER_r_ok( src, n ), "read" );
return dest;
}
#else /* if __has_builtin( __builtin___memmove_chk ) */
void * memmove( void * dest,
const void * src,
size_t n )
{
__CPROVER_assert( __CPROVER_w_ok( dest, n ), "write" );
__CPROVER_assert( __CPROVER_r_ok( src, n ), "read" );
return dest;
}
#endif /* if __has_builtin( __builtin___memmove_chk ) */

View File

@ -0,0 +1,260 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_stubs.c
* @brief Implements the functions declared in sigv4_stubs.h
*/
#include <sigv4.h>
#include <sigv4_internal.h>
#include <sigv4_stubs.h>
SigV4Status_t scanValue( const char * pDate,
const char formatChar,
size_t readLoc,
size_t lenToRead,
SigV4DateTime_t * pDateElements )
{
SigV4Status_t returnStatus = SigV4InvalidParameter;
const char * pMonthNames[] = MONTH_NAMES;
const char * pLoc = pDate + readLoc;
size_t remainingLenToRead = lenToRead;
int32_t result = 0;
static flag = 0;
assert( pDate != NULL );
assert( pDateElements != NULL );
if( formatChar == '*' )
{
remainingLenToRead = 0U;
}
/* Determine if month value is non-numeric. */
if( ( formatChar == 'M' ) && ( remainingLenToRead == MONTH_ASCII_LEN ) )
{
returnStatus = SigV4Success;
remainingLenToRead = 0U;
}
/* Interpret integer value of numeric representation. */
while( ( remainingLenToRead > 0U ) && ( *pLoc >= '0' ) && ( *pLoc <= '9' ) )
{
result = ( result * 10 ) + ( int32_t ) ( *pLoc - '0' );
remainingLenToRead--;
pLoc += 1;
}
if( remainingLenToRead != 0U )
{
LogError( ( "Parsing Error: Expected numerical string of type '%%%d%c', "
"but received '%.*s'.",
( int ) lenToRead,
formatChar,
( int ) lenToRead,
pLoc ) );
returnStatus = SigV4ISOFormattingError;
}
if( returnStatus != SigV4ISOFormattingError )
{
addToDate( formatChar,
result,
pDateElements );
}
return returnStatus;
}
void addToDate( const char formatChar,
int32_t result,
SigV4DateTime_t * pDateElements )
{
assert( pDateElements != NULL );
assert( result >= 0 );
switch( formatChar )
{
case 'Y':
pDateElements->tm_year = result;
break;
case 'M':
pDateElements->tm_mon = result;
break;
case 'D':
pDateElements->tm_mday = result;
break;
case 'h':
pDateElements->tm_hour = result;
break;
case 'm':
pDateElements->tm_min = result;
break;
case 's':
pDateElements->tm_sec = result;
break;
default:
/* Do not assign values for skipped characters ('*'), or
* unrecognized format specifiers. */
break;
}
}
SigV4Status_t writeLineToCanonicalRequest( const char * pLine,
size_t lineLen,
CanonicalContext_t * pCanonicalContext )
{
SigV4Status_t ret = SigV4InsufficientMemory;
assert( ( pCanonicalContext != NULL ) && ( pCanonicalContext->pBufCur != NULL ) );
if( pCanonicalContext->bufRemaining >= ( lineLen + 1U ) )
{
assert( __CPROVER_w_ok( pCanonicalContext->pBufCur, ( lineLen + 1U ) ) );
ret = SigV4Success;
}
return ret;
}
SigV4Status_t encodeURI( const char * pUri,
size_t uriLen,
char * pCanonicalURI,
size_t * canonicalURILen,
bool encodeSlash,
bool doubleEncodeEquals )
{
SigV4Status_t returnStatus = SigV4Success;
assert( pUri != NULL );
assert( pCanonicalURI != NULL );
assert( canonicalURILen != NULL );
if( nondet_bool() )
{
returnStatus = SigV4Success;
}
else
{
returnStatus = SigV4InsufficientMemory;
}
return returnStatus;
}
SigV4Status_t generateCanonicalQuery( const char * pQuery,
size_t queryLen,
CanonicalContext_t * pCanonicalContext )
{
SigV4Status_t returnStatus = SigV4InsufficientMemory;
assert( ( pCanonicalContext != NULL ) && ( pCanonicalContext->pBufCur != NULL ) );
if( nondet_bool() )
{
__CPROVER_assume( pCanonicalContext->bufRemaining < SIGV4_PROCESSING_BUFFER_LENGTH );
returnStatus = SigV4Success;
}
else
{
returnStatus = SigV4InsufficientMemory;
}
return returnStatus;
}
SigV4Status_t generateCanonicalAndSignedHeaders( const char * pHeaders,
size_t headersLen,
uint32_t flags,
CanonicalContext_t * pCanonicalContext,
char ** pSignedHeaders,
size_t * pSignedHeadersLen )
{
SigV4Status_t returnStatus = SigV4InsufficientMemory;
assert( pHeaders != NULL );
assert( pCanonicalContext != NULL );
assert( pCanonicalContext->pBufCur != NULL );
assert( pSignedHeaders != NULL );
assert( pSignedHeadersLen != NULL );
if( nondet_bool() )
{
/* The signed headers are assumed to start at a location within the processing
* buffer and should not end past the length of the processing buffer. */
size_t headersLen, headerOffset, bytesConsumed;
char * pHeaders = NULL;
__CPROVER_assume( pCanonicalContext->bufRemaining < SIGV4_PROCESSING_BUFFER_LENGTH );
bytesConsumed = SIGV4_PROCESSING_BUFFER_LENGTH - pCanonicalContext->bufRemaining;
__CPROVER_assume( headerOffset < bytesConsumed );
__CPROVER_assume( headersLen > 0U && headersLen <= bytesConsumed - headerOffset );
pHeaders = ( char * ) pCanonicalContext->pBufProcessing + headerOffset;
*pSignedHeadersLen = headersLen;
*pSignedHeaders = pHeaders;
returnStatus = SigV4Success;
}
else
{
returnStatus = SigV4InsufficientMemory;
}
return returnStatus;
}
SigV4Status_t copyHeaderStringToCanonicalBuffer( const char * pData,
size_t dataLen,
uint32_t flags,
char separator,
CanonicalContext_t * canonicalRequest )
{
SigV4Status_t returnStatus = SigV4Success;
size_t buffRemaining;
__CPROVER_assume( pData != NULL );
__CPROVER_assume( dataLen > 0 );
__CPROVER_assume( dataLen < CBMC_MAX_OBJECT_SIZE );
assert( ( pData != NULL ) && ( dataLen > 0 ) );
assert( canonicalRequest != NULL );
assert( canonicalRequest->pBufCur != NULL );
buffRemaining = canonicalRequest->bufRemaining;
if( buffRemaining < dataLen )
{
returnStatus = SigV4InsufficientMemory;
}
return returnStatus;
}

View File

@ -0,0 +1,61 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_config.h
* @brief Config values for testing the SigV4 for AWS IoT Library.
*/
#ifndef SIGV4_CONFIG_H_
#define SIGV4_CONFIG_H_
#include <stdio.h>
#ifdef DISABLE_LOGGING
#ifndef LogError
#define LogError( message )
#endif
#ifndef LogWarn
#define LogWarn( message )
#endif
#ifndef LogInfo
#define LogInfo( message )
#endif
#ifndef LogDebug
#define LogDebug( message )
#endif
#else /* ! DISABLE_LOGGING */
#define LogError( message ) printf( "Error: " ); printf message; printf( "\n" )
#define LogWarn( message ) printf( "Warn: " ); printf message; printf( "\n" )
#define LogInfo( message ) printf( "Info: " ); printf message; printf( "\n" )
#define LogDebug( message ) printf( "Debug: " ); printf message; printf( "\n" )
#endif /* DISABLE_LOGGING */
#endif /* SIGV4_CONFIG_H_ */

View File

@ -0,0 +1,58 @@
# Include filepaths for source and include.
include( ${MODULE_ROOT_DIR}/sigv4FilePaths.cmake )
find_package(OpenSSL REQUIRED)
# ==================== Define your project name (edit) ========================
set(project_name "sigv4")
# ===================== Create your mock here (edit) ========================
# ================= Create the library under test here (edit) ==================
# list the files you would like to test here
list(APPEND real_source_files
${SIGV4_SOURCES}
)
# list the directories the module under test includes
list(APPEND real_include_directories
.
${SIGV4_INCLUDE_PUBLIC_DIRS}
"${CMAKE_CURRENT_LIST_DIR}/../include"
)
# ===================== Create UnitTest Code here (edit) =====================
# list the directories your test needs to include
list(APPEND test_include_directories
.
${SIGV4_INCLUDE_PUBLIC_DIRS}
)
# ============================= (end edit) ===================================
set(real_name "${project_name}_real")
create_real_library(${real_name}
"${real_source_files}"
"${real_include_directories}"
"${mock_name}"
)
list(APPEND utest_link_list
lib${real_name}.a
)
list(APPEND utest_dep_list
${real_name}
)
set(utest_name "${project_name}_utest")
set(utest_source "${project_name}_utest.c")
create_test(${utest_name}
${utest_source}
"${utest_link_list}"
"${utest_dep_list}"
"${test_include_directories}"
)
target_link_libraries(${utest_name} OpenSSL::SSL)

View File

@ -0,0 +1,58 @@
# Macro utility to clone the CMock submodule.
macro( clone_cmock )
find_package( Git REQUIRED )
message( "Cloning submodule CMock." )
execute_process( COMMAND rm -rf ${CMOCK_DIR}
COMMAND ${GIT_EXECUTABLE} submodule update --checkout --init --recursive ${CMOCK_DIR}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE CMOCK_CLONE_RESULT )
if( NOT ${CMOCK_CLONE_RESULT} STREQUAL "0" )
message( FATAL_ERROR "Failed to clone CMock submodule." )
endif()
endmacro()
# Macro utility to add library targets for Unity and CMock to build configuration.
macro( add_cmock_targets )
# Build Configuration for CMock and Unity libraries.
list( APPEND CMOCK_INCLUDE_DIRS
"${CMOCK_DIR}/vendor/unity/src/"
"${CMOCK_DIR}/vendor/unity/extras/fixture/src"
"${CMOCK_DIR}/vendor/unity/extras/memory/src"
"${CMOCK_DIR}/src"
)
add_library(cmock STATIC
"${CMOCK_DIR}/src/cmock.c"
)
set_target_properties(cmock PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
POSITION_INDEPENDENT_CODE ON
COMPILE_FLAGS "-Og"
)
target_include_directories(cmock PUBLIC
${CMOCK_DIR}/src
${CMOCK_DIR}/vendor/unity/src/
${CMOCK_DIR}/examples
${CMOCK_INCLUDE_DIRS}
)
add_library(unity STATIC
"${CMOCK_DIR}/vendor/unity/src/unity.c"
"${CMOCK_DIR}/vendor/unity/extras/fixture/src/unity_fixture.c"
"${CMOCK_DIR}/vendor/unity/extras/memory/src/unity_memory.c"
)
set_target_properties(unity PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
POSITION_INDEPENDENT_CODE ON
)
target_include_directories(unity PUBLIC
${CMOCK_INCLUDE_DIRS}
)
target_link_libraries(cmock unity)
endmacro()

View File

@ -0,0 +1,111 @@
/*
* SigV4 Library v1.2.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* @file sigv4_config.h
* @brief The default values for configuration macros used by the SigV4 Library.
*
* @note This file should NOT be modified. If custom values are needed for any
* configuration macros, a sigv4_config.h file should be provided to the SigV4
* Library to override the default values defined in this file. To use
* the custom config file, the preprocessor macro SIGV4_DO_NOT_USE_CUSTOM_CONFIG
* must NOT be set.
*/
#ifndef SIGV4_CONFIG_H_
#define SIGV4_CONFIG_H_
#define LOGGING_LEVEL_DEBUG 1
/* @[code_example_loggingmacros] */
/************* Define Logging Macros using printf function ***********/
#define PrintfError( ... ) printf( "[%d] Error: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" )
#define PrintfWarn( ... ) printf( "[%d] Warn: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" )
#define PrintfInfo( ... ) printf( "[%d] Info: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" )
#define PrintfDebug( ... ) printf( "[%d] Debug: ", __LINE__ ); printf( __VA_ARGS__ ); printf( "\n" )
#ifdef LOGGING_LEVEL_ERROR
#define LogError( message ) PrintfError message
#elif defined( LOGGING_LEVEL_WARNING )
#define LogError( message ) PrintfError message
#define LogWarn( message ) PrintfWarn message
#elif defined( LOGGING_LEVEL_INFO )
#define LogError( message ) PrintfError message
#define LogWarn( message ) PrintfWarn message
#define LogInfo( message ) PrintfInfo message
#elif defined( LOGGING_LEVEL_DEBUG )
#define LogError( message ) PrintfError message
#define LogWarn( message ) PrintfWarn message
#define LogInfo( message ) PrintfInfo message
#define LogDebug( message ) PrintfDebug message
#endif /* ifdef LOGGING_LEVEL_ERROR */
/**************************************************/
/* @[code_example_loggingmacros] */
/**
* @brief Macro defining the size of the internal buffer used for incremental
* canonicalization and hashing.
*
* A buffer of this size in bytes is declared on the stack. It should be be
* large enough for the digest output of the specified hash function.
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `1024`
*/
#ifndef SIGV4_PROCESSING_BUFFER_LENGTH
#define SIGV4_PROCESSING_BUFFER_LENGTH 428
#endif
/**
* @brief Macro defining the maximum number of headers in the request, used to
* assist the library in sorting header fields during canonicalization.
*
* This macro should be updated if the number of request headers the application
* wishes to sign is higher or lower than the default value (100).
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `100`
*/
#ifndef SIGV4_MAX_HTTP_HEADER_COUNT
#define SIGV4_MAX_HTTP_HEADER_COUNT 7U
#endif
/**
* @brief Macro defining the maximum number of query key/value pairs, used to
* assist the library in sorting query keys during canonicalization.
*
* This macro should be updated if the number of query key/value pairs the
* application wishes to sign is higher or lower than the default value (100).
*
* <b>Possible values:</b> Any positive 32 bit integer. <br>
* <b>Default value:</b> `100`
*/
#ifndef SIGV4_MAX_QUERY_PAIR_COUNT
#define SIGV4_MAX_QUERY_PAIR_COUNT 5U
#endif
#endif /* ifndef SIGV4_CONFIG_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
# Taken from amazon-freertos repository
cmake_minimum_required(VERSION 3.13)
set(BINARY_DIR ${CMAKE_BINARY_DIR})
# reset coverage counters
execute_process(
COMMAND lcov --directory ${CMAKE_BINARY_DIR}
--base-directory ${CMAKE_BINARY_DIR}
--zerocounters
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/coverage
)
# make the initial/baseline capture a zeroed out files
execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR}
--base-directory ${CMAKE_BINARY_DIR}
--initial
--capture
--rc lcov_branch_coverage=1
--rc genhtml_branch_coverage=1
--output-file=${CMAKE_BINARY_DIR}/base_coverage.info
)
file(GLOB files "${CMAKE_BINARY_DIR}/bin/tests/*")
set(REPORT_FILE ${CMAKE_BINARY_DIR}/utest_report.txt)
file(WRITE ${REPORT_FILE} "")
# execute all files in bin directory, gathering the output to show it in CI
foreach(testname ${files})
get_filename_component(test
${testname}
NAME_WLE
)
message("Running ${testname}")
execute_process(COMMAND ${testname} OUTPUT_FILE ${CMAKE_BINARY_DIR}/${test}_out.txt)
file(READ ${CMAKE_BINARY_DIR}/${test}_out.txt CONTENTS)
file(APPEND ${REPORT_FILE} "${CONTENTS}")
endforeach()
# generate Junit style xml output
execute_process(COMMAND ruby
${CMOCK_DIR}/vendor/unity/auto/parse_output.rb
-xml ${REPORT_FILE}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
# capture data after running the tests
execute_process(
COMMAND lcov --capture
--rc lcov_branch_coverage=1
--rc genhtml_branch_coverage=1
--base-directory ${CMAKE_BINARY_DIR}
--directory ${CMAKE_BINARY_DIR}
--output-file ${CMAKE_BINARY_DIR}/second_coverage.info
)
# combile baseline results (zeros) with the one after running the tests
execute_process(
COMMAND lcov --base-directory ${CMAKE_BINARY_DIR}
--directory ${CMAKE_BINARY_DIR}
--add-tracefile ${CMAKE_BINARY_DIR}/base_coverage.info
--add-tracefile ${CMAKE_BINARY_DIR}/second_coverage.info
--output-file ${CMAKE_BINARY_DIR}/coverage.info
--no-external
--rc lcov_branch_coverage=1
)
execute_process(
COMMAND genhtml --rc lcov_branch_coverage=1
--branch-coverage
--output-directory ${CMAKE_BINARY_DIR}/coverage
${CMAKE_BINARY_DIR}/coverage.info
)

View File

@ -0,0 +1,168 @@
# Taken from amazon-freertos repository
#function to create the test executable
function(create_test test_name
test_src
link_list
dep_list
include_list)
set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks")
include (CTest)
get_filename_component(test_src_absolute ${test_src} ABSOLUTE)
add_custom_command(OUTPUT ${test_name}_runner.c
COMMAND ruby
${CMOCK_DIR}/vendor/unity/auto/generate_test_runner.rb
${MODULE_ROOT_DIR}/tools/cmock/project.yml
${test_src_absolute}
${test_name}_runner.c
DEPENDS ${test_src}
)
add_executable(${test_name} ${test_src} ${test_name}_runner.c)
set_target_properties(${test_name} PROPERTIES
COMPILE_FLAG "-O0 -ggdb"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/tests"
INSTALL_RPATH_USE_LINK_PATH TRUE
LINK_FLAGS " \
-Wl,-rpath,${CMAKE_BINARY_DIR}/lib \
-Wl,-rpath,${CMAKE_CURRENT_BINARY_DIR}/lib"
)
target_include_directories(${test_name} PUBLIC
${mocks_dir}
${include_list}
)
target_link_directories(${test_name} PUBLIC
${CMAKE_CURRENT_BINARY_DIR}
)
# link all libraries sent through parameters
foreach(link IN LISTS link_list)
target_link_libraries(${test_name} ${link})
endforeach()
# add dependency to all the dep_list parameter
foreach(dependency IN LISTS dep_list)
add_dependencies(${test_name} ${dependency})
target_link_libraries(${test_name} ${dependency})
endforeach()
target_link_libraries(${test_name} -lgcov unity)
target_link_directories(${test_name} PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/lib
)
add_test(NAME ${test_name}
COMMAND ${CMAKE_BINARY_DIR}/bin/tests/${test_name}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endfunction()
# Run the C preprocessor on target files.
# Takes a CMAKE list of arguments to pass to the C compiler
function(preprocess_mock_list mock_name file_list compiler_args)
set_property(GLOBAL PROPERTY ${mock_name}_processed TRUE)
foreach (target_file IN LISTS file_list)
# Has to be TARGET ALL so the file is pre-processed before CMOCK
# is executed on the file.
add_custom_command(OUTPUT ${target_file}.backup
COMMAND scp ${target_file} ${target_file}.backup
VERBATIM COMMAND ${CMAKE_C_COMPILER} -E ${compiler_args} ${target_file} > ${target_file}.out
)
add_custom_target(pre_${mock_name}
COMMAND mv ${target_file}.out ${target_file}
DEPENDS ${target_file}.backup
)
endforeach()
# Clean up temporary files that were created.
# First we test to see if the backup file still exists. If it does we revert
# the change made to the original file.
foreach (target_file IN LISTS file_list)
add_custom_command(TARGET ${mock_name}
POST_BUILD
COMMAND test ! -e ${target_file}.backup || mv ${target_file}.backup ${target_file}
)
endforeach()
endfunction()
# Generates a mock library based on a module's header file
# places the generated source file in the build directory
# @param mock_name: name of the target name
# @param mock_list list of header files to mock
# @param cmock_config configuration file of the cmock framework
# @param mock_include_list include list for the target
# @param mock_define_list special definitions to control compilation
function(create_mock_list mock_name
mock_list
cmock_config
mock_include_list
mock_define_list)
set(mocks_dir "${CMAKE_CURRENT_BINARY_DIR}/mocks")
add_library(${mock_name} SHARED)
foreach (mock_file IN LISTS mock_list)
get_filename_component(mock_file_abs
${mock_file}
ABSOLUTE
)
get_filename_component(mock_file_name
${mock_file}
NAME_WLE
)
get_filename_component(mock_file_dir
${mock_file}
DIRECTORY
)
add_custom_command (
OUTPUT ${mocks_dir}/mock_${mock_file_name}.c
COMMAND ruby
${CMOCK_DIR}/lib/cmock.rb
-o${cmock_config} ${mock_file_abs}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
target_sources(${mock_name} PUBLIC
${mocks_dir}/mock_${mock_file_name}.c
)
target_include_directories(${mock_name} PUBLIC
${mock_file_dir}
)
endforeach()
target_include_directories(${mock_name} PUBLIC
${mocks_dir}
${mock_include_list}
)
set_target_properties(${mock_name} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib
POSITION_INDEPENDENT_CODE ON
)
target_compile_definitions(${mock_name} PUBLIC
${mock_define_list}
)
target_link_libraries(${mock_name} cmock unity)
endfunction()
function(create_real_library target
src_file
real_include_list
mock_name)
add_library(${target} STATIC
${src_file}
)
target_include_directories(${target} PUBLIC
${real_include_list}
)
set_target_properties(${target} PROPERTIES
COMPILE_FLAGS "-Wextra -Wpedantic \
-fprofile-arcs -ftest-coverage -fprofile-generate \
-Wno-unused-but-set-variable"
LINK_FLAGS "-fprofile-arcs -ftest-coverage \
-fprofile-generate "
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib
)
if(NOT(mock_name STREQUAL ""))
add_dependencies(${target} ${mock_name})
target_link_libraries(${target}
-l${mock_name}
-lgcov
)
endif()
endfunction()

View File

@ -0,0 +1,26 @@
# Taken from amazon-freertos repository
:cmock:
:mock_prefix: mock_
:when_no_prototypes: :warn
:enforce_strict_ordering: TRUE
:plugins:
- :ignore
- :ignore_arg
- :expect_any_args
- :array
- :callback
- :return_thru_ptr
:callback_include_count: true # include a count arg when calling the callback
:callback_after_arg_check: false # check arguments before calling the callback
:treat_as:
uint8: HEX8
uint16: HEX16
uint32: UINT32
int8: INT8
bool: UINT8
:includes: # This will add these includes to each mock.
- <stdbool.h>
- <stdint.h>
:treat_externs: :exclude # Now the extern-ed functions will be mocked.
:weak: __attribute__((weak))
:treat_externs: :include

View File

@ -0,0 +1,79 @@
# Static code analysis for AWS SigV4 Library
This directory is made for the purpose of statically testing the MISRA C:2012 compliance of AWS SigV4 Library using
[Synopsys Coverity](https://www.synopsys.com/software-integrity/security-testing/static-analysis-sast.html) static analysis tool.
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
building a binary for the tool to analyze.
> **Note**
For generating the report as outlined below, we have used Coverity version 2018.09.
For details regarding the suppressed violations in the report (which can be generated using the instructions described below), please
see the [MISRA.md](https://github.com/aws/SigV4-for-AWS-IoT-embedded-sdk/blob/main/MISRA.md) file.
## Getting Started
### Prerequisites
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).
To compile and run the Coverity target successfully, you must have the following:
1. CMake version > 3.13.0 (You can check whether you have this by typing `cmake --version`)
2. GCC compiler
- You can see the downloading and installation instructions [here](https://gcc.gnu.org/install/).
3. Download the repo and include the submodules using the following commands.
- `git clone --recurse-submodules git@github.com:aws/SigV4-for-AWS-IoT-embedded-sdk.git ./SigV4-for-AWS-IoT-embedded-sdk`
- `cd ./SigV4-for-AWS-IoT-embedded-sdk`
- `git submodule update --checkout --init --recursive`
### To build and run coverity:
Go to the root directory of the library and run the following commands in terminal:
1. Update the compiler configuration in Coverity
~~~
cov-configure --force --compiler cc --comptype gcc
~~~
2. Create the build files using CMake in a `build` directory
~~~
cmake -B build -S test
~~~
3. Go to the build directory and copy the coverity configuration file
~~~
cd build/
~~~
4. Build the static analysis target
~~~
cov-build --emit-complementary-info --dir cov-out make coverity_analysis
~~~
5. Go to the Coverity output directory (`cov-out`) and begin Coverity static analysis
~~~
cd cov-out/
cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')"
~~~
6. Format the errors in HTML format so that it is more readable while removing the test and build directory from the report
~~~
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out;
~~~
7. Format the errors in JSON format to perform a jq query to get a simplified list of any exceptions.
NOTE: A blank output means there are no defects that aren't being suppressed by the config or inline comments.
~~~
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json;
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n";
jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr;
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n";
~~~
For your convenience the commands above are below to be copy/pasted into a UNIX command friendly terminal.
~~~
cov-configure --force --compiler cc --comptype gcc;
cmake -B build -S test;
cd build/;
cov-build --emit-complementary-info --dir cov-out make coverity_analysis;
cd cov-out/
cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')";
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out;
cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json;
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n";
jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr;
echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n";
cd ../../;
~~~
You should now have the HTML formatted violations list in a directory named `build/cov-out/html-output`.
With the current configuration and the provided project, you should not see any deviations.

View File

@ -0,0 +1,33 @@
// MISRA C-2012 Rules
{
version : "2.0",
standard : "c2012",
title: "Coverity MISRA Configuration",
deviations : [
// Disable the following rules.
{
deviation: "Directive 4.9",
reason: "Allow inclusion of function like macros. Asserts and logging use function like macros."
},
{
deviation: "Rule 2.4",
reason: "Allow unused tags. Some compilers warn if types are not tagged."
},
{
deviation: "Rule 2.5",
reason: "Allow unused macros."
},
{
deviation: "Rule 3.1",
reason: "Allow nested comments. C++ style `//` comments are used in example code within Doxygen documentation blocks."
},
{
deviation: "Rule 8.7",
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."
},
{
deviation: "Rule 11.5",
reason: "Allow casts from void *. Functions with void * parameters are used while sorting."
},
]
}