├── .github
├── .cSpellWords.txt
├── CONTRIBUTING.md
├── memory_statistics_config.json
├── pull_request_template.md
└── workflows
│ ├── ci.yml
│ ├── doxygen-generation.yml
│ └── release.yml
├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── LICENSE
├── MISRA.md
├── README.md
├── SECURITY.md
├── cspell.config.yaml
├── docs
├── doxygen
│ ├── config.doxyfile
│ ├── include
│ │ └── size_table.md
│ ├── layout.xml
│ ├── pages.dox
│ ├── porting.dox
│ └── style.css
└── plantuml
│ ├── fleet_provisioning_operations.pu
│ └── images
│ └── fleet_provisioning_operations.png
├── fleetprovisioningFilePaths.cmake
├── manifest.yml
├── source
├── fleet_provisioning.c
└── include
│ ├── fleet_provisioning.h
│ └── fleet_provisioning_config_defaults.h
├── test
├── CMakeLists.txt
├── cbmc
│ ├── .gitignore
│ ├── include
│ │ └── README.md
│ ├── proofs
│ │ ├── FleetProvisioning_GetRegisterThingTopic
│ │ │ ├── FleetProvisioning_GetRegisterThingTopic_harness.c
│ │ │ ├── Makefile
│ │ │ ├── README.md
│ │ │ ├── cbmc-proof.txt
│ │ │ └── cbmc-viewer.json
│ │ ├── FleetProvisioning_MatchTopic
│ │ │ ├── FleetProvisioning_MatchTopic_harness.c
│ │ │ ├── Makefile
│ │ │ ├── README.md
│ │ │ ├── cbmc-proof.txt
│ │ │ └── cbmc-viewer.json
│ │ ├── Makefile-project-defines
│ │ ├── Makefile-project-targets
│ │ ├── Makefile-project-testing
│ │ ├── Makefile-template-defines
│ │ ├── Makefile.common
│ │ ├── README.md
│ │ ├── lib
│ │ │ ├── __init__.py
│ │ │ ├── print_tool_versions.py
│ │ │ └── summarize.py
│ │ ├── prepare.py
│ │ └── run-cbmc-proofs.py
│ ├── sources
│ │ └── README.md
│ └── stubs
│ │ └── README.md
├── include
│ └── fleet_provisioning_config.h
└── unit-test
│ ├── CMakeLists.txt
│ ├── fleet_provisioning_utest.c
│ └── unity_build.cmake
└── tools
├── coverity
├── README.md
└── misra.config
└── unity
├── coverage.cmake
├── create_test.cmake
└── project.yml
/.github/.cSpellWords.txt:
--------------------------------------------------------------------------------
1 | cbmc
2 | CBMC
3 | cbor
4 | CBOR
5 | cmock
6 | Cmock
7 | CMock
8 | CMOCK
9 | coremqtt
10 | coverity
11 | Coverity
12 | CSDK
13 | ctest
14 | DCMOCK
15 | DCOV
16 | DDisable
17 | decihours
18 | Decihours
19 | DECIHOURS
20 | DNDEBUG
21 | DUNITY
22 | getpacketid
23 | isystem
24 | lcov
25 | misra
26 | Misra
27 | MISRA
28 | MQTT
29 | mypy
30 | nondet
31 | Nondet
32 | NONDET
33 | pylint
34 | pytest
35 | pyyaml
36 | sinclude
37 | UNACKED
38 | unpadded
39 | Unpadded
40 | UNPADDED
41 | UNSUB
42 | UNSUBACK
43 | unsubscriptions
44 | utest
45 | vect
46 | Vect
47 | VECT
48 | Wextra
49 | Wunused
50 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
4 | documentation, we greatly value feedback and contributions from our community.
5 |
6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
7 | information to effectively respond to your bug report or contribution.
8 |
9 |
10 | ## Reporting Bugs/Feature Requests
11 |
12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features.
13 |
14 | When filing an issue, please check [existing open](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/issues), or [recently closed](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/issues?q=is%3Aissue+is%3Aclosed) issues to make sure somebody else hasn't already
15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
16 |
17 | * A reproducible test case or series of steps
18 | * The version of our code being used
19 | * Any modifications you've made relevant to the bug
20 | * Anything unusual about your environment or deployment
21 |
22 |
23 | ## Contributing via Pull Requests
24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
25 |
26 | 1. You are working against the latest source on the *main* branch.
27 | 1. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
28 | 1. You open an issue to discuss any significant work - we would hate for your time to be wasted.
29 |
30 | To send us a pull request, please:
31 |
32 | 1. Fork the repository.
33 | 1. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
34 | 1. Ensure that your contributions conform to the [style guide](https://docs.aws.amazon.com/embedded-csdk/202011.00/lib-ref/docs/doxygen/output/html/guide_developer_styleguide.html).
35 | 1. Format your code with uncrustify, using the config available in [FreeRTOS/CI-CD-Github-Actions](https://github.com/FreeRTOS/CI-CD-Github-Actions/blob/main/formatting/uncrustify.cfg).
36 | 1. Ensure local tests pass.
37 | 1. Commit to your fork using clear commit messages.
38 | 1. Send us a pull request, answering any default questions in the pull request interface.
39 | 1. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
40 |
41 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
42 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
43 |
44 |
45 | ## Finding contributions to work on
46 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/labels?q=help+wanted) issues is a great place to start.
47 |
48 |
49 | ## Code of Conduct
50 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
51 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
52 | opensource-codeofconduct@amazon.com with any additional questions or comments.
53 |
54 |
55 | ## Security issue notifications
56 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](https://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public Github issue.
57 |
58 |
59 | ## Licensing
60 |
61 | See the [LICENSE](../LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
62 |
63 | We may ask you to sign a [Contributor License Agreement (CLA)](https://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
64 |
--------------------------------------------------------------------------------
/.github/memory_statistics_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib_name": "AWS IoT Fleet Provisioning",
3 | "src": [
4 | "source/fleet_provisioning.c"
5 | ],
6 | "include": [
7 | "source/include"
8 | ],
9 | "compiler_flags": [
10 | "FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | *Issue #, if available:*
2 |
3 | *Description of changes:*
4 |
5 |
6 | By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.
7 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI Checks
2 | on:
3 | push:
4 | branches: ["**"]
5 | pull_request:
6 | branches: [main]
7 | workflow_dispatch:
8 | jobs:
9 | unittest:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Clone This Repo
13 | uses: actions/checkout@v3
14 | - name: Build
15 | run: |
16 | sudo apt-get install -y lcov
17 | cmake -S test -B build/ \
18 | -G "Unix Makefiles" \
19 | -DCMAKE_BUILD_TYPE=Debug \
20 | -DBUILD_CLONE_SUBMODULES=ON \
21 | -DUNITTEST=1 \
22 | -DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG'
23 | make -C build/ all
24 | - name: Test
25 | run: |
26 | cd build/
27 | ctest -E system --output-on-failure
28 | cd ..
29 | - name: Run Coverage
30 | run: |
31 | make -C build/ coverage
32 | declare -a EXCLUDE=("\*test\*" "\*CMakeCCompilerId\*" "\*mocks\*")
33 | echo ${EXCLUDE[@]} | xargs lcov --rc lcov_branch_coverage=1 -r build/coverage.info -o build/coverage.info
34 | lcov --rc lcov_branch_coverage=1 --list build/coverage.info
35 | - name: Check Coverage
36 | uses: FreeRTOS/CI-CD-Github-Actions/coverage-cop@main
37 | with:
38 | coverage-file: ./build/coverage.info
39 | branch-coverage-min: 100
40 | line-coverage-min: 100
41 | build-with-default-config:
42 | runs-on: ubuntu-latest
43 | steps:
44 | - name: Clone This Repo
45 | uses: actions/checkout@v3
46 | - name: Build
47 | run: |
48 | cmake -S test -B build/ \
49 | -G "Unix Makefiles" \
50 | -DCMAKE_BUILD_TYPE=Debug \
51 | -DCMAKE_C_FLAGS='-Wall -Wextra -Werror -DFLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG'
52 | make -C build/ all
53 | complexity:
54 | runs-on: ubuntu-latest
55 | steps:
56 | - uses: actions/checkout@v3
57 | - name: Check complexity
58 | uses: FreeRTOS/CI-CD-Github-Actions/complexity@main
59 | with:
60 | path: ./
61 | doxygen:
62 | runs-on: ubuntu-latest
63 | steps:
64 | - uses: actions/checkout@v3
65 | - name: Run doxygen build
66 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen@main
67 | with:
68 | path: ./
69 | spell-check:
70 | runs-on: ubuntu-latest
71 | steps:
72 | - name: Clone This Repo
73 | uses: actions/checkout@v3
74 | - name: Run spellings check
75 | uses: FreeRTOS/CI-CD-Github-Actions/spellings@main
76 | with:
77 | path: ./
78 | formatting:
79 | runs-on: ubuntu-20.04
80 | steps:
81 | - uses: actions/checkout@v3
82 | - name: Check formatting
83 | uses: FreeRTOS/CI-CD-Github-Actions/formatting@main
84 | with:
85 | path: ./
86 | git-secrets:
87 | runs-on: ubuntu-latest
88 | steps:
89 | - uses: actions/checkout@v3
90 | - name: Checkout awslabs/git-secrets
91 | uses: actions/checkout@v3
92 | with:
93 | repository: awslabs/git-secrets
94 | ref: master
95 | path: git-secrets
96 | - name: Install git-secrets
97 | run: cd git-secrets && sudo make install && cd ..
98 | - name: Run git-secrets
99 | run: |
100 | git-secrets --register-aws
101 | git-secrets --scan
102 | memory_statistics:
103 | runs-on: ubuntu-latest
104 | steps:
105 | - uses: actions/checkout@v3
106 | with:
107 | submodules: "recursive"
108 | - name: Measure sizes
109 | uses: FreeRTOS/CI-CD-Github-Actions/memory_statistics@main
110 | with:
111 | config: .github/memory_statistics_config.json
112 | check_against: docs/doxygen/include/size_table.md
113 |
114 | link-verifier:
115 | runs-on: ubuntu-latest
116 | steps:
117 | - uses: actions/checkout@v3
118 | - name: Check Links
119 | env:
120 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
121 | uses: FreeRTOS/CI-CD-Github-Actions/link-verifier@main
122 |
123 | verify-manifest:
124 | runs-on: ubuntu-latest
125 | steps:
126 | - uses: actions/checkout@v3
127 | with:
128 | submodules: true
129 | fetch-depth: 0
130 |
131 | - name: Run manifest verifier
132 | uses: FreeRTOS/CI-CD-GitHub-Actions/manifest-verifier@main
133 | with:
134 | path: ./
135 | fail-on-incorrect-version: true
136 |
137 | proof_ci:
138 | runs-on: cbmc_ubuntu-latest_16-core
139 | steps:
140 | - name: Set up CBMC runner
141 | uses: FreeRTOS/CI-CD-Github-Actions/set_up_cbmc_runner@main
142 | with:
143 | cbmc_version: "6.1.1"
144 | - name: Run CBMC
145 | uses: FreeRTOS/CI-CD-Github-Actions/run_cbmc@main
146 | with:
147 | proofs_dir: test/cbmc/proofs
148 |
--------------------------------------------------------------------------------
/.github/workflows/doxygen-generation.yml:
--------------------------------------------------------------------------------
1 | name: Doxygen Generation
2 | on:
3 | push:
4 | branches: [main]
5 | workflow_dispatch:
6 | jobs:
7 | doxygen-generation:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Doxygen generation
11 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main
12 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release automation
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | commit_id:
7 | description: 'Commit ID to tag and create a release for'
8 | required: true
9 | version_number:
10 | description: 'Release Version Number (Eg, v1.0.0)'
11 | required: true
12 |
13 | jobs:
14 | tag-commit:
15 | name: Generate SBOM and tag commit
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Checkout code
19 | uses: actions/checkout@v4
20 | with:
21 | ref: ${{ github.event.inputs.commit_id }}
22 | - name: Configure git identity
23 | run: |
24 | git config --global user.name ${{ github.actor }}
25 | git config --global user.email ${{ github.actor }}@users.noreply.github.com
26 | - name: create a new branch that references commit id
27 | run: git checkout -b ${{ github.event.inputs.version_number }} ${{ github.event.inputs.commit_id }}
28 | - name: Generate SBOM
29 | uses: FreeRTOS/CI-CD-Github-Actions/sbom-generator@main
30 | with:
31 | repo_path: ./
32 | source_path: ./source
33 | - name: commit SBOM file
34 | run: |
35 | git add .
36 | git commit -m 'Update SBOM'
37 | git push -u origin ${{ github.event.inputs.version_number }}
38 | - name: Tag Commit and Push to remote
39 | run: |
40 | git tag ${{ github.event.inputs.version_number }} -a -m "AWS IoT Fleet Provisioning ${{ github.event.inputs.version_number }}"
41 | git push origin --tags
42 | - name: Verify tag on remote
43 | run: |
44 | git tag -d ${{ github.event.inputs.version_number }}
45 | git remote update
46 | git checkout tags/${{ github.event.inputs.version_number }}
47 | git diff ${{ github.event.inputs.commit_id }} tags/${{ github.event.inputs.version_number }}
48 | create-zip:
49 | needs: tag-commit
50 | name: Create ZIP and verify package for release asset.
51 | runs-on: ubuntu-latest
52 | steps:
53 | - name: Install ZIP tools
54 | run: sudo apt-get install zip unzip
55 | - name: Checkout code
56 | uses: actions/checkout@v4
57 | with:
58 | ref: ${{ github.event.inputs.commit_id }}
59 | path: Fleet-Provisioning-for-AWS-IoT-embedded-sdk
60 | submodules: recursive
61 | - name: Checkout disabled submodules
62 | run: |
63 | cd Fleet-Provisioning-for-AWS-IoT-embedded-sdk
64 | git submodule update --init --checkout --recursive
65 | - name: Create ZIP
66 | run: |
67 | zip -r Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip Fleet-Provisioning-for-AWS-IoT-embedded-sdk -x "*.git*"
68 | ls ./
69 | - name: Validate created ZIP
70 | run: |
71 | mkdir zip-check
72 | mv Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip zip-check
73 | cd zip-check
74 | unzip Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip -d Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}
75 | ls Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}
76 | diff -r -x "*.git*" Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/ ../Fleet-Provisioning-for-AWS-IoT-embedded-sdk/
77 | cd ../
78 | - name: Build
79 | run: |
80 | cd zip-check/Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Fleet-Provisioning-for-AWS-IoT-embedded-sdk
81 | sudo apt-get install -y lcov
82 | cmake -S test -B build/ \
83 | -G "Unix Makefiles" \
84 | -DCMAKE_BUILD_TYPE=Debug \
85 | -DBUILD_CLONE_SUBMODULES=ON \
86 | -DCMAKE_C_FLAGS='--coverage -Wall -Wextra -Werror -DNDEBUG'
87 | make -C build/ all
88 | - name: Test
89 | run: |
90 | cd zip-check/Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/build/
91 | ctest -E system --output-on-failure
92 | cd ..
93 | - name: Create artifact of ZIP
94 | uses: actions/upload-artifact@v4
95 | with:
96 | name: Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
97 | path: zip-check/Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
98 | deploy-doxygen:
99 | needs: tag-commit
100 | name: Deploy doxygen documentation
101 | runs-on: ubuntu-latest
102 | steps:
103 | - name: Doxygen generation
104 | uses: FreeRTOS/CI-CD-Github-Actions/doxygen-generation@main
105 | with:
106 | ref: ${{ github.event.inputs.version_number }}
107 | add_release: "true"
108 | create-release:
109 | needs:
110 | - create-zip
111 | - deploy-doxygen
112 | name: Create Release and Upload Release Asset
113 | runs-on: ubuntu-latest
114 | steps:
115 | - name: Create Release
116 | id: create_release
117 | uses: actions/create-release@v1
118 | env:
119 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
120 | with:
121 | tag_name: ${{ github.event.inputs.version_number }}
122 | release_name: ${{ github.event.inputs.version_number }}
123 | body: Release ${{ github.event.inputs.version_number }} of AWS IoT Fleet Provisioning.
124 | draft: false
125 | prerelease: false
126 | - name: Download ZIP artifact
127 | uses: actions/download-artifact@v4
128 | with:
129 | name: Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
130 | - name: Upload Release Asset
131 | id: upload-release-asset
132 | uses: actions/upload-release-asset@v1
133 | env:
134 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
135 | with:
136 | upload_url: ${{ steps.create_release.outputs.upload_url }}
137 | asset_path: ./Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
138 | asset_name: Fleet-Provisioning-for-AWS-IoT-embedded-sdk-${{ github.event.inputs.version_number }}.zip
139 | asset_content_type: application/zip
140 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore documentation output.
2 | **/docs/**/output/*
3 |
4 | # Ignore CMake build directory.
5 | build/
6 |
7 | # Ignore build artifacts.
8 | *.o
9 |
10 | # Ignore code coverage artifacts.
11 | *.gcda
12 | *.gcno
13 | *.gcov
14 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "test/unit-test/Unity"]
2 | path = test/unit-test/Unity
3 | url = https://github.com/ThrowTheSwitch/Unity
4 | update = none
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog for AWS IoT Fleet Provisioning Library
2 |
3 | ## v1.2.1 (June 2024)
4 |
5 | ### Other
6 | - Fix doxygen deployment on Github.
7 |
8 | ## v1.2.0 (May 2024)
9 |
10 | ### Other
11 | - [#41](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/pull/41) Fix warnings with ARM GCC compiler when compiled with -Wextra
12 | - [#40](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/pull/40) Add CBMC proof check action in Github CI
13 | - [#39](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/pull/39) MISRA C:2012 compliance checked with Coverity static analysis version 2023.6.1
14 | - [#34](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/pull/34) Update doxygen version to 1.9.6
15 |
16 | ## v1.1.0 (October 2022)
17 |
18 | ### Updates
19 | - [#26](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/pull/26) MISRA C:2012 Compliance Update
20 | - [#25](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/pull/25) Update CBMC starter kit
21 |
22 | ## v1.0.1 (December 2021)
23 |
24 | ### Updates
25 | - [#20](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/pull/20) Update Doxygen version to 1.9.2
26 |
27 | ## v1.0.0 (August 2021)
28 |
29 | This is the first release of the AWS IoT Fleet Provisioning Library.
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
21 |
--------------------------------------------------------------------------------
/MISRA.md:
--------------------------------------------------------------------------------
1 | # MISRA Compliance
2 |
3 | The Fleet Provisioning Library files conform to the [MISRA C:2012](https://www.misra.org.uk)
4 | guidelines, with some noted exceptions. Compliance is checked with Coverity static analysis.
5 | The specific deviations, suppressed inline, are listed below.
6 |
7 | Additionally, [MISRA configuration file](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/blob/main/tools/coverity/misra.config) contains the project wide deviations.
8 |
9 | ### Suppressed with Coverity Comments
10 | To find the violation references in the source files run grep on the source code
11 | with ( Assuming rule 11.4 violation; with justification in point 2 ):
12 | ```
13 | grep 'MISRA Ref 11.4.2' . -rI
14 | ```
15 |
16 | *None.*
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AWS IoT Fleet Provisioning Library
2 |
3 | **[API Documentation Pages for current and previous releases of this library can be found here](https://aws.github.io/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/)**
4 |
5 | The Fleet Provisioning library enables you to provision IoT devices without
6 | device certificates using the [Fleet Provisioning feature of AWS IoT Core][a1].
7 | For an overview of provisioning options available, see [Device
8 | provisioning][a2]. This library has no dependencies on any additional libraries
9 | other than the standard C library, and therefore, can be used with any MQTT
10 | library. This library is distributed under the [MIT Open Source License][a3].
11 |
12 | [a1]:
13 | https://docs.aws.amazon.com/iot/latest/developerguide/provision-wo-cert.html
14 | [a2]: https://docs.aws.amazon.com/iot/latest/developerguide/iot-provision.html
15 | [a3]: LICENSE
16 |
17 | This library has gone through code quality checks including verification that no
18 | function has a [GNU Complexity][a4] score over 8, and checks against deviations
19 | from mandatory rules in the [MISRA coding standard][a5]. Deviations from the
20 | MISRA C:2012 guidelines are documented under [MISRA Deviations][a6]. This
21 | library has also undergone static code analysis using [Coverity static
22 | analysis][a7], and validation of memory safety through the [CBMC automated
23 | reasoning tool][a8].
24 |
25 | [a4]: https://www.gnu.org/software/complexity/manual/complexity.html
26 | [a5]: https://www.misra.org.uk
27 | [a6]: MISRA.md
28 | [a7]: https://scan.coverity.com/
29 | [a8]: https://www.cprover.org/cbmc/
30 |
31 | See memory requirements for this library [here][a9].
32 |
33 | [a9]: ./docs/doxygen/include/size_table.md
34 |
35 | **AWS IoT Fleet Provisioning Library v1.2.1
36 | [source code](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/tree/v1.2.1/source)
37 | is part of the
38 | [FreeRTOS 202406.00 LTS](https://github.com/FreeRTOS/FreeRTOS-LTS/tree/202406.00-LTS)
39 | release.**
40 |
41 | ## AWS IoT Fleet Provisioning Library Config File
42 |
43 | The AWS IoT Fleet Provisioning Library exposes build configuration macros that
44 | are required for building the library. A list of all the configurations and
45 | their default values are defined in [fleet_provisioning_config_defaults.h][b1].
46 | To provide custom values for the configuration macros, a config file named
47 | `fleet_provisioning_config.h` can be provided by the application to the library.
48 |
49 | [b1]: source/include/fleet_provisioning_config_defaults.h
50 |
51 | By default, a `fleet_provisioning_config.h` config file is required to build the
52 | library. To disable this requirement and build the library with default
53 | configuration values, provide `FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG` as a
54 | compile time preprocessor macro.
55 |
56 | **Thus, the Fleet Provisioning library can be built by either**:
57 |
58 | - Defining a `fleet_provisioning_config.h` file in the application, and adding
59 | it to the include directories list of the library.
60 |
61 | **OR**
62 |
63 | - Defining the `FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG` preprocessor macro
64 | for the library build.
65 |
66 | ## Building the Library
67 |
68 | The [fleetprovisioningFilePaths.cmake][c1] file contains the information of all
69 | source files and the header include paths required to build the Fleet
70 | Provisioning library.
71 |
72 | [c1]: fleetprovisioningFilePaths.cmake
73 |
74 | As mentioned in the previous section, either a custom config file (i.e.
75 | `fleet_provisioning_config.h`) or `FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG`
76 | macro needs to be provided to build the Fleet Provisioning library.
77 |
78 | For a CMake example of building the Fleet Provisioning library with the
79 | `fleetprovisioningFilePaths.cmake` file, refer to the `coverity_analysis`
80 | library target in [test/CMakeLists.txt][c2] file.
81 |
82 | [c2]: test/CMakeLists.txt
83 |
84 | ## Building Unit Tests
85 |
86 | ### Platform Prerequisites
87 |
88 | - For running unit tests:
89 | - **C90 compiler** like gcc.
90 | - **CMake 3.13.0 or later**.
91 | - For running the coverage target, **gcov** and **lcov** are additionally
92 | required.
93 |
94 | ### Steps to build **Unit Tests**
95 |
96 | 1. Go to the root directory of this repository.
97 |
98 | 1. Run the _cmake_ command:
99 | `cmake -S test -B build -DBUILD_CLONE_SUBMODULES=ON`.
100 |
101 | 1. Run this command to build the library and unit tests: `make -C build all`.
102 |
103 | 1. The generated test executables will be present in `build/bin/tests` folder.
104 |
105 | 1. Run `cd build && ctest` to execute all tests and view the test run summary.
106 |
107 | ## CBMC
108 |
109 | To learn more about CBMC and proofs specifically, review the training material
110 | [here](https://model-checking.github.io/cbmc-training).
111 |
112 | The `test/cbmc/proofs` directory contains CBMC proofs.
113 |
114 | In order to run these proofs you will need to install CBMC and other tools by
115 | following the instructions
116 | [here](https://model-checking.github.io/cbmc-training/installation.html).
117 |
118 | ## Reference examples
119 |
120 | The [AWS IoT Embedded C-SDK repository][e1] contains a demo showing the use of
121 | the AWS IoT Fleet Provisioning Library on a POSIX platform [here][e2].
122 |
123 | [e1]: https://github.com/aws/aws-iot-device-sdk-embedded-C
124 | [e2]:
125 | https://github.com/aws/aws-iot-device-sdk-embedded-C/tree/main/demos/fleet_provisioning/fleet_provisioning_with_csr
126 |
127 | ## Generating documentation
128 |
129 | The Doxygen references were created using Doxygen version 1.9.6. To generate the
130 | Doxygen pages, please run the following command from the root of this
131 | repository:
132 |
133 | ```sh
134 | doxygen docs/doxygen/config.doxyfile
135 | ```
136 |
137 | ## Contributing
138 |
139 | See [CONTRIBUTING.md][g1] for information on contributing.
140 |
141 | [g1]: .github/CONTRIBUTING.md
142 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | ## Reporting a Vulnerability
2 |
3 | If you discover a potential security issue in this project, we ask that you notify AWS/Amazon Security
4 | via our [vulnerability reporting page](https://aws.amazon.com/security/vulnerability-reporting/) or directly via email to aws-security@amazon.com.
5 | Please do **not** create a public Github issue.
6 |
--------------------------------------------------------------------------------
/cspell.config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | $schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
3 | version: '0.2'
4 | # Allows things like stringLength
5 | allowCompoundWords: true
6 |
7 | # Read files not to spell check from the git ignore
8 | useGitignore: true
9 |
10 | # Language settings for C
11 | languageSettings:
12 | - caseSensitive: false
13 | enabled: true
14 | languageId: c
15 | locale: "*"
16 |
17 | # Add a dictionary, and the path to the word list
18 | dictionaryDefinitions:
19 | - name: freertos-words
20 | path: '.github/.cSpellWords.txt'
21 | addWords: true
22 |
23 | dictionaries:
24 | - freertos-words
25 |
26 | # Paths and files to ignore
27 | ignorePaths:
28 | - 'dependency'
29 | - 'docs'
30 | - 'ThirdParty'
31 | - 'History.txt'
32 |
--------------------------------------------------------------------------------
/docs/doxygen/include/size_table.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Code Size of AWS IoT Fleet Provisioning (example generated with GCC for ARM Cortex-M) |
4 |
5 |
6 | File |
7 | With -O1 Optimization |
8 | With -Os Optimization |
9 |
10 |
11 | fleet_provisioning.c |
12 | 1.0K |
13 | 0.9K |
14 |
15 |
16 | Total estimates |
17 | 1.0K |
18 | 0.9K |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/doxygen/layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/docs/doxygen/pages.dox:
--------------------------------------------------------------------------------
1 | /**
2 | @mainpage Overview
3 | @anchor fleet_provisioning
4 | @brief AWS IoT Fleet Provisioning Library
5 |
6 | > By using AWS IoT fleet provisioning, AWS IoT can generate and securely deliver device certificates and private keys to your devices when they connect to AWS IoT for the first time. AWS IoT provides client certificates that are signed by the Amazon Root certificate authority (CA).
7 | — Description of Fleet Provisioning from AWS IoT documentation
8 |
9 | For an overview of device provisioning options available with AWS IoT, see
10 | [Device Provisioning](https://docs.aws.amazon.com/iot/latest/developerguide/provision-wo-cert.html).
11 |
12 | AWS IoT Fleet Provisioning allows you to provision devices without
13 | pre-installed unique client certificates. There are two ways to use Fleet
14 | Provisioning: by claim, or by trusted user. If provisioning by claim, devices
15 | used a provisioning claim certificate and private key registered with AWS IoT
16 | to obtain unique device certificates. If provisioning by trusted user, a
17 | trusted user, such as an end user or installation technician, uses a mobile
18 | app to configure the device in its deployed location.
19 |
20 | There are two options for obtaining unique client certificates with AWS IoT
21 | Fleet Provisioning: CreateCertificateFromCsr and CreateKeysAndCertificate.
22 | CreateCertificateFromCsr allows the device to obtain a certificate by providing
23 | a certificate signing request, keeping the private key secure on the device.
24 | CreateKeysAndCertificate provides a new certificate and corresponding private
25 | key.
26 |
27 | @section fleet_provisioning_memory_requirements Memory Requirements
28 | @brief Memory requirements of the AWS IoT Fleet Provisioning Library.
29 |
30 | @include{doc} size_table.md
31 | */
32 |
33 | /**
34 | @page fleet_provisioning_design Design
35 | AWS IoT Fleet Provisioning Library Design
36 |
37 | The AWS IoT Fleet Provisioning library provides macros and functions to
38 | assemble and parse MQTT topic strings reserved for the Fleet Provisioning
39 | feature of AWS IoT core. Applications can use this library in conjunction with
40 | any MQTT library to interact with the AWS IoT Fleet Provisioning APIs.
41 |
42 | The diagram below demonstrates the happy path an application can take to use
43 | the Fleet Provisioning library, a MQTT library, and a JSON or CBOR library to
44 | interact with the AWS IoT Fleet Provisioning APIs.
45 |
46 | \image html fleet_provisioning_operations.png "Fleet Provisioning Library example operation diagram" width=90%
47 | */
48 |
49 | /**
50 | @page fleet_provisioning_config Configurations
51 | @brief Configurations of the AWS IoT Fleet Provisioning Library.
52 |
54 | @par configpagestyle
55 |
56 | Configuration settings are C pre-processor constants. They can be set with a
57 | `\#define` in the config file (`fleet_provisioning_config.h`) or by using a
58 | compiler option such as -D in gcc.
59 |
60 | @section FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG
61 | @copydoc FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG
62 |
63 | @section fleet_provisioning_logerror LogError
64 | @copydoc LogError
65 |
66 | @section fleet_provisioning_logwarn LogWarn
67 | @copydoc LogWarn
68 |
69 | @section fleet_provisioning_loginfo LogInfo
70 | @copydoc LogInfo
71 |
72 | @section fleet_provisioning_logdebug LogDebug
73 | @copydoc LogDebug
74 | */
75 |
76 | /**
77 | @page fleet_provisioning_functions Functions
78 | @brief Primary functions of the AWS IoT Fleet Provisioning Library:
79 | @subpage fleet_provisioning_getregisterthingtopic_function
80 | @subpage fleet_provisioning_matchtopic_function
81 |
82 | @page fleet_provisioning_getregisterthingtopic_function FleetProvisioning_GetRegisterThingTopic
83 | @snippet fleet_provisioning.h declare_fleet_provisioning_getregisterthingtopic
84 | @copydoc FleetProvisioning_GetRegisterThingTopic
85 |
86 | @page fleet_provisioning_matchtopic_function FleetProvisioning_MatchTopic
87 | @snippet fleet_provisioning.h declare_fleet_provisioning_matchtopic
88 | @copydoc FleetProvisioning_MatchTopic
89 | */
90 |
91 |
93 | /**
94 | @defgroup fleet_provisioning_enum_types Enumerated Types
95 | @brief Enumerated types of the AWS IoT Fleet Provisioning Library
96 | */
97 |
98 | /**
99 | @defgroup fleet_provisioning_constants Constants
100 | @brief Constants defined in the AWS IoT Fleet Provisioning Library
101 | */
102 |
--------------------------------------------------------------------------------
/docs/doxygen/porting.dox:
--------------------------------------------------------------------------------
1 | /**
2 | @page fleet_provisioning_porting Porting Guide
3 | @brief Guide for porting the AWS IoT Fleet Provisioning Library to a new
4 | platform.
5 |
6 | @section fleet_provisioning_porting_config Configuration Macros
7 | @brief Configuration macros that can be set in the config header
8 | `fleet_provisioning_config.h`, or passed in as compiler options.
9 |
10 | The following optional logging macros are used throughout the library:
11 | - @ref LogError
12 | - @ref LogWarn
13 | - @ref LogInfo
14 | - @ref LogDebug
15 |
16 | @see [Configurations](@ref fleet_provisioning_config) for more information.
17 |
18 | @note Regardless of whether the above macros are defined in
19 | `fleet_provisioning_config.h` or passed as compiler options, by default the
20 | `fleet_provisioning_config.h` file is needed to build the AWS IoT Fleet
21 | Provisioning Library. To disable this requirement and build the library with
22 | default configuration values, provide
23 | `FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG` as a compile time preprocessor
24 | macro.
25 | */
26 |
--------------------------------------------------------------------------------
/docs/doxygen/style.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Stylesheet for Doxygen HTML output.
3 | *
4 | * This file defines styles for custom elements in the header/footer and
5 | * overrides some of the default Doxygen styles.
6 | *
7 | * Styles in this file do not affect the treeview sidebar.
8 | */
9 |
10 | /* Set the margins to place a small amount of whitespace on the left and right
11 | * side of the page. */
12 | div.contents {
13 | margin-left:4em;
14 | margin-right:4em;
15 | }
16 |
17 | /* Justify text in paragraphs. */
18 | p {
19 | text-align: justify;
20 | }
21 |
22 | /* Style of section headings. */
23 | h1 {
24 | border-bottom: 1px solid #879ECB;
25 | color: #354C7B;
26 | font-size: 160%;
27 | font-weight: normal;
28 | padding-bottom: 4px;
29 | padding-top: 8px;
30 | }
31 |
32 | /* Style of subsection headings. */
33 | h2:not(.memtitle):not(.groupheader) {
34 | font-size: 125%;
35 | margin-bottom: 0px;
36 | margin-top: 16px;
37 | padding: 0px;
38 | }
39 |
40 | /* Style of paragraphs immediately after subsection headings. */
41 | h2 + p {
42 | margin: 0px;
43 | padding: 0px;
44 | }
45 |
46 | /* Style of subsection headings. */
47 | h3 {
48 | font-size: 100%;
49 | margin-bottom: 0px;
50 | margin-left: 2em;
51 | margin-right: 2em;
52 | }
53 |
54 | /* Style of paragraphs immediately after subsubsection headings. */
55 | h3 + p {
56 | margin-top: 0px;
57 | margin-left: 2em;
58 | margin-right: 2em;
59 | }
60 |
61 | /* Style of the prefix "AWS IoT Device SDK C" that appears in the header. */
62 | #csdkprefix {
63 | color: #757575;
64 | }
65 |
66 | /* Style of the "Return to main page" link that appears in the header. */
67 | #returntomain {
68 | padding: 0.5em;
69 | }
70 |
71 | /* Style of the dividers on Configuration Settings pages. */
72 | div.configpagedivider {
73 | margin-left: 0px !important;
74 | margin-right: 0px !important;
75 | margin-top: 20px !important;
76 | }
77 |
78 | /* Style of configuration setting names. */
79 | dl.section.user ~ h1 {
80 | border-bottom: none;
81 | color: #000000;
82 | font-family: monospace, fixed;
83 | font-size: 16px;
84 | margin-bottom: 0px;
85 | margin-left: 2em;
86 | margin-top: 1.5em;
87 | }
88 |
89 | /* Style of paragraphs on a configuration settings page. */
90 | dl.section.user ~ * {
91 | margin-bottom: 10px;
92 | margin-left: 4em;
93 | margin-right: 4em;
94 | margin-top: 0px;
95 | }
96 |
97 | /* Hide the configuration setting marker. */
98 | dl.section.user {
99 | display: none;
100 | }
101 |
102 | /* Overrides for code fragments and lines. */
103 | div.fragment {
104 | background: #ffffff;
105 | border: none;
106 | padding: 5px;
107 | }
108 |
109 | div.line {
110 | color: #3a3a3a;
111 | }
112 |
113 | /* Overrides for code syntax highlighting colors. */
114 | span.comment {
115 | color: #008000;
116 | }
117 |
118 | span.keyword, span.keywordtype, span.keywordflow {
119 | color: #0000ff;
120 | }
121 |
122 | span.preprocessor {
123 | color: #50015a;
124 | }
125 |
126 | span.stringliteral, span.charliteral {
127 | color: #800c0c;
128 | }
129 |
130 | a.code, a.code:visited, a.line, a.line:visited {
131 | color: #496194;
132 | }
133 |
134 | div.image img[src="fleet_provisioning_operations.png"] {
135 | max-width: 1000px;
136 | }
137 |
--------------------------------------------------------------------------------
/docs/plantuml/fleet_provisioning_operations.pu:
--------------------------------------------------------------------------------
1 | @startuml
2 | skinparam dpi 300
3 | skinparam classFontSize 8
4 | skinparam classFontName Helvetica
5 | autonumber
6 |
7 | participant "User Application" as App
8 | participant "Fleet Provisioning Library" as FleetProv
9 | participant "MQTT Client" as MQTT
10 | participant "JSON/CBOR Library" as JSON
11 |
12 | activate App
13 |
14 | App -> MQTT : Connect to AWS IoT broker with claim credentials
15 |
16 | activate MQTT
17 | MQTT -> App : Connected
18 | deactivate MQTT
19 |
20 | opt If using CreateCertificateFromCsr
21 | App -> App : Securely generate keys and corresponding CSR
22 |
23 | App -> JSON : Generate CreateCertificateFromCsr request payload
24 |
25 | activate JSON
26 | JSON -> App : Request payload
27 | deactivate JSON
28 |
29 | App -> FleetProv : Get Accepted and Rejected Topic Strings\n for CreateCertificateFromCsr
30 |
31 | activate FleetProv
32 | FleetProv -> App : Accepted and Rejected Topic Strings
33 | deactivate FleetProv
34 |
35 | App -> MQTT : Subscribe to CreateCertificateFromCsr Accepted and Rejected Topics
36 |
37 | activate MQTT
38 | MQTT -> App : Subscription Successful
39 | deactivate MQTT
40 |
41 | App -> FleetProv : Get CreateCertificateFromCsr Publish Topic String
42 |
43 | activate FleetProv
44 | FleetProv -> App : Publish Topic String
45 | deactivate FleetProv
46 |
47 | App -> MQTT : Publish Request
48 |
49 | activate MQTT
50 | MQTT -> App : Published
51 | MQTT -> App : Incoming Publish Message Received
52 | deactivate MQTT
53 |
54 | App -> FleetProv : Is this a Fleet Provisioning CreateCertificateFromCsr\naccepted Message?
55 |
56 | activate FleetProv
57 | FleetProv -> App : Yes
58 | deactivate FleetProv
59 |
60 | App -> JSON : Parse response payload
61 |
62 | activate JSON
63 | JSON -> App : Certificate, certificate id, certificate ownership token
64 | deactivate JSON
65 |
66 | App -> App : Securely store certificate
67 |
68 | else If using CreateKeysAndCertificate
69 |
70 | App -> FleetProv : Generate Accepted and Rejected Topic Strings for RegisterThing
71 |
72 | activate FleetProv
73 | FleetProv -> App : Accepted and Rejected Topic Strings
74 | deactivate FleetProv
75 |
76 | App -> MQTT : Subscribe to CreateKeysAndCertificate Accepted and Rejected Topics
77 |
78 | activate MQTT
79 | MQTT -> App : Subscription Successful
80 | deactivate MQTT
81 |
82 | App -> FleetProv : Get CreateKeysAndCertificate Publish Topic String
83 |
84 | activate FleetProv
85 | FleetProv -> App : Publish Topic String
86 | deactivate FleetProv
87 |
88 | App -> MQTT : Publish Request
89 |
90 | activate MQTT
91 | MQTT -> App : Published
92 | MQTT -> App : Incoming Publish Message Received
93 | deactivate MQTT
94 |
95 | App -> FleetProv : Is this a Fleet Provisioning CreateKeysAndCertificate\naccepted Message?
96 |
97 | activate FleetProv
98 | FleetProv -> App : Yes
99 | deactivate FleetProv
100 |
101 | App -> JSON : Parse response payload
102 |
103 | activate JSON
104 | JSON -> App : Private key, certificate, certificate id, certificate ownership token
105 | deactivate JSON
106 |
107 | App -> App : Securely store key and certificate
108 |
109 | end
110 |
111 | App -> JSON : Generate RegisterThing request payload
112 |
113 | activate JSON
114 | JSON -> App : Request payload
115 | deactivate JSON
116 | App -> FleetProv : Generate Accepted and Rejected Topic Strings for RegisterThing
117 |
118 | activate FleetProv
119 | FleetProv -> App : Accepted and Rejected Topic Strings
120 | deactivate FleetProv
121 |
122 | App -> MQTT : Subscribe to RegisterThing Accepted and Rejected Topics
123 |
124 | activate MQTT
125 | MQTT -> App : Subscription Successful
126 | deactivate MQTT
127 |
128 | App -> FleetProv : Get RegisterThing Publish Topic String
129 |
130 | activate FleetProv
131 | FleetProv -> App : Publish Topic String
132 | deactivate FleetProv
133 |
134 | App -> MQTT : Publish Request
135 |
136 | activate MQTT
137 | MQTT -> App : Published
138 | MQTT -> App : Incoming Publish Message Received
139 | deactivate MQTT
140 |
141 | App -> FleetProv : Is this a Fleet Provisioning RegisterThing accepted Message?
142 |
143 | activate FleetProv
144 | FleetProv -> App : Yes
145 | deactivate FleetProv
146 |
147 | App -> JSON : Parse response payload
148 |
149 | activate JSON
150 | JSON -> App : Thing name, device configuration
151 | deactivate JSON
152 |
153 | App -> MQTT : Disconnect from AWS IoT broker
154 |
155 | activate MQTT
156 | MQTT -> App : Disconnected
157 | deactivate MQTT
158 |
159 | App -> MQTT : Connect to AWS IoT broker with newly provisioned credentials
160 |
161 | activate MQTT
162 | MQTT -> App : Connected
163 | deactivate MQTT
164 | deactivate App
165 | @enduml
166 |
--------------------------------------------------------------------------------
/docs/plantuml/images/fleet_provisioning_operations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/629ec2a21d91ade13bfb995aace2223b36c4cd2e/docs/plantuml/images/fleet_provisioning_operations.png
--------------------------------------------------------------------------------
/fleetprovisioningFilePaths.cmake:
--------------------------------------------------------------------------------
1 | # This file is to add source files and include directories
2 | # into variables so that it can be reused from different repositories
3 | # in their Cmake based build system by including this file.
4 | #
5 | # Files specific to the repository such as test runner, platform tests
6 | # are not added to the variables.
7 |
8 | # Fleet Provisioning library source files.
9 | set( FLEET_PROVISIONING_SOURCES
10 | "${CMAKE_CURRENT_LIST_DIR}/source/fleet_provisioning.c" )
11 |
12 | # Fleet Provisioning library public include directories.
13 | set( FLEET_PROVISIONING_INCLUDE_PUBLIC_DIRS
14 | "${CMAKE_CURRENT_LIST_DIR}/source/include" )
15 |
--------------------------------------------------------------------------------
/manifest.yml:
--------------------------------------------------------------------------------
1 | name: "Fleet-Provisioning-for-AWS-IoT-embedded-sdk"
2 | version: "v1.2.1"
3 | description: |
4 | "Library for using the Fleet Provisioning feature of AWS IoT Core on embedded devices.\n"
5 | license: "MIT"
6 |
--------------------------------------------------------------------------------
/source/fleet_provisioning.c:
--------------------------------------------------------------------------------
1 | /*
2 | * AWS IoT Fleet Provisioning v1.2.1
3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | *
5 | * SPDX-License-Identifier: MIT
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | * this software and associated documentation files (the "Software"), to deal in
9 | * the Software without restriction, including without limitation the rights to
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | * the Software, and to permit persons to whom the Software is furnished to do so,
12 | * subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /**
26 | * @file fleet_provisioning.c
27 | * @brief Implementation of the AWS IoT Fleet Provisioning Library.
28 | */
29 |
30 | /* Standard includes. */
31 | #include
32 | #include
33 | #include
34 |
35 | /* Fleet Provisioning API include. */
36 | #include "fleet_provisioning.h"
37 |
38 | /**
39 | * @brief Identifier for which of the topic suffixes for a given format and
40 | * Fleet Provisioning MQTT API.
41 | */
42 | typedef enum
43 | {
44 | TopicPublish,
45 | TopicAccepted,
46 | TopicRejected,
47 | TopicInvalidSuffix
48 | } TopicSuffix_t;
49 |
50 | /**
51 | * @brief Identifier for which of the topics in each Fleet Provisioning MQTT API.
52 | */
53 | typedef enum
54 | {
55 | TopicJsonPublish,
56 | TopicJsonAccepted,
57 | TopicJsonRejected,
58 | TopicCborPublish,
59 | TopicCborAccepted,
60 | TopicCborRejected,
61 | TopicInvalidFormatSuffix
62 | } TopicFormatSuffix_t;
63 |
64 | /**
65 | * @brief Get the topic length for a given RegisterThing topic.
66 | *
67 | * @param[in] templateNameLength the length of the template name registered with
68 | * AWS IoT.
69 | * @param[in] format The RegisterThing API format to use.
70 | * @param[in] topic The RegisterThing API format to use.
71 | *
72 | * @return the template length for the given RegisterThing topic.
73 | */
74 | static uint16_t getRegisterThingTopicLength( uint16_t templateNameLength,
75 | FleetProvisioningFormat_t format,
76 | FleetProvisioningApiTopics_t topic );
77 |
78 | /**
79 | * @brief Write the given piece of the topic to the remaining buffer and advance
80 | * the remaining buffer pointer.
81 | *
82 | * The caller is responsible for assuring that there is enough space remaining
83 | * in the buffer to write the given string.
84 | *
85 | * @param[in,out] pBufferCursor Pointer to the remaining buffer.
86 | * @param[in] fragment The piece of the topic string to write.
87 | * @param[in] length The length of @p fragment.
88 | */
89 | static void writeTopicFragmentAndAdvance( char ** pBufferCursor,
90 | const char * fragment,
91 | uint16_t length );
92 |
93 | /**
94 | * @brief Check the parameters for FleetProvisioning_GetRegisterThingTopic().
95 | *
96 | * @param[in] pTopicBuffer The buffer to write the topic string into.
97 | * @param[in] format The desired RegisterThing format.
98 | * @param[in] topic The desired RegisterThing topic.
99 | * @param[in] pTemplateName The name of the provisioning template configured
100 | * with AWS IoT.
101 | * @param[in] templateNameLength The length of @p pTemplateName.
102 | * @param[in] pOutLength The length of the topic string written to
103 | * the buffer.
104 | *
105 | * @return FleetProvisioningSuccess if no errors are found with the parameters;
106 | * FleetProvisioningBadParameter otherwise.
107 | */
108 | static FleetProvisioningStatus_t GetRegisterThingTopicCheckParams( const char * pTopicBuffer,
109 | FleetProvisioningFormat_t format,
110 | FleetProvisioningApiTopics_t topic,
111 | const char * pTemplateName,
112 | uint16_t templateNameLength,
113 | const uint16_t * pOutLength );
114 |
115 | /**
116 | * @brief Match the suffix from the remaining topic string and return the
117 | * corresponding suffix.
118 | *
119 | * Suffix: empty, /accepted, or /rejected.
120 | *
121 | * @param[in] pRemainingTopic The remaining portion of the topic.
122 | * @param[in] remainingLength The remaining length of the topic.
123 | *
124 | * @return The matching #TopicSuffix_t.
125 | */
126 | static TopicSuffix_t parseTopicSuffix( const char * pRemainingTopic,
127 | uint16_t remainingLength );
128 |
129 | /**
130 | * @brief Match the format and suffix from the remaining topic string and
131 | * return the corresponding format and suffix.
132 | *
133 | * Format: json or cbor.
134 | * Suffix: empty, /accepted, or /rejected.
135 | *
136 | * @param[in] pRemainingTopic The remaining portion of the topic.
137 | * @param[in] remainingLength The remaining length of the topic.
138 | *
139 | * @return The matching #TopicFormatSuffix_t.
140 | */
141 | static TopicFormatSuffix_t parseTopicFormatSuffix( const char * pRemainingTopic,
142 | uint16_t remainingLength );
143 |
144 | /**
145 | * @brief Match a topic string with the CreateCertificateFromCsr topics.
146 | *
147 | * @param[in] pTopic The topic string to match.
148 | * @param[in] topicLength The length of the topic string.
149 | *
150 | * @return The matching #FleetProvisioningTopic_t if the topic string is a
151 | * Fleet Provisioning CreateCertificateFromCsr topic, else
152 | * FleetProvisioningInvalidTopic.
153 | */
154 | static FleetProvisioningTopic_t parseCreateCertificateFromCsrTopic( const char * pTopic,
155 | uint16_t topicLength );
156 |
157 | /**
158 | * @brief Match a topic string with the CreateKeysAndCertificate topics.
159 | *
160 | * @param[in] pTopic The topic string to match.
161 | * @param[in] topicLength The length of the topic string.
162 | *
163 | * @return The matching FleetProvisioningTopic_t if the topic string is a
164 | * Fleet Provisioning CreateKeysAndCertificate topic, else
165 | * FleetProvisioningInvalidTopic.
166 | */
167 | static FleetProvisioningTopic_t parseCreateKeysAndCertificateTopic( const char * pTopic,
168 | uint16_t topicLength );
169 |
170 | /**
171 | * @brief Match a topic string with the RegisterThing topics.
172 | *
173 | * @param[in] pTopic The topic string to match.
174 | * @param[in] topicLength The length of the topic string.
175 | *
176 | * @return The matching #FleetProvisioningTopic_t if the topic string is a
177 | * Fleet Provisioning RegisterThing topic, else
178 | * FleetProvisioningInvalidTopic.
179 | */
180 | static FleetProvisioningTopic_t parseRegisterThingTopic( const char * pTopic,
181 | uint16_t topicLength );
182 |
183 | /**
184 | * @brief Check if the remaining buffer starts with a specified string. If so,
185 | * moves the remaining buffer pointer past the matched section and updates the
186 | * remaining length.
187 | *
188 | * @param[in,out] pBufferCursor Pointer to the remaining portion of the buffer.
189 | * @param[in,out] pRemainingLength The remaining length of the buffer.
190 | * @param[in] matchString The string to match against.
191 | * @param[in] matchLength The length of @p matchString.
192 | *
193 | * @return FleetProvisioningSuccess if the string matches and is skipped over;
194 | * FleetProvisioningNoMatch otherwise.
195 | */
196 | static FleetProvisioningStatus_t consumeIfMatch( const char ** pBufferCursor,
197 | uint16_t * pRemainingLength,
198 | const char * matchString,
199 | uint16_t matchLength );
200 |
201 | /**
202 | * @brief Move the remaining topic pointer past the template name in the
203 | * unparsed topic so far, and update the remaining topic length.
204 | *
205 | * The end of thing name is marked by a forward slash. A zero length thing name
206 | * is not valid.
207 | *
208 | * This function extracts the same template name from the following topic strings:
209 | * - $aws/provisioning-templates/TEMPLATE_NAME/provision/json/accepted
210 | * - $aws/provisioning-templates/TEMPLATE_NAME
211 | * The second topic is not a valid Fleet Provisioning topic and the matching
212 | * will fail when we try to match the bridge part.
213 | *
214 | * @param[in,out] pTopicCursor Pointer to the remaining topic string.
215 | * @param[in,out] pRemainingLength Pointer to the length of the remaining topic string.
216 | *
217 | * @return FleetProvisioningSuccess if a valid template name is skipped over;
218 | * FleetProvisioningNoMatch otherwise.
219 | */
220 | static FleetProvisioningStatus_t consumeTemplateName( const char ** pTopicCursor,
221 | uint16_t * pRemainingLength );
222 | /*-----------------------------------------------------------*/
223 |
224 | static uint16_t getRegisterThingTopicLength( uint16_t templateNameLength,
225 | FleetProvisioningFormat_t format,
226 | FleetProvisioningApiTopics_t topic )
227 | {
228 | uint16_t topicLength = 0U;
229 |
230 | assert( ( templateNameLength != 0U ) &&
231 | ( templateNameLength <= FP_TEMPLATENAME_MAX_LENGTH ) );
232 | assert( ( format == FleetProvisioningJson ) || ( format == FleetProvisioningCbor ) );
233 | assert( ( topic >= FleetProvisioningPublish ) && ( topic <= FleetProvisioningRejected ) );
234 |
235 | topicLength = FP_REGISTER_API_LENGTH_PREFIX +
236 | templateNameLength +
237 | FP_REGISTER_API_LENGTH_BRIDGE;
238 |
239 | if( format == FleetProvisioningJson )
240 | {
241 | topicLength += FP_API_LENGTH_JSON_FORMAT;
242 | }
243 |
244 | if( format == FleetProvisioningCbor )
245 | {
246 | topicLength += FP_API_LENGTH_CBOR_FORMAT;
247 | }
248 |
249 | if( topic == FleetProvisioningAccepted )
250 | {
251 | topicLength += FP_API_LENGTH_ACCEPTED_SUFFIX;
252 | }
253 |
254 | if( topic == FleetProvisioningRejected )
255 | {
256 | topicLength += FP_API_LENGTH_REJECTED_SUFFIX;
257 | }
258 |
259 | return topicLength;
260 | }
261 | /*-----------------------------------------------------------*/
262 |
263 | static void writeTopicFragmentAndAdvance( char ** pBufferCursor,
264 | const char * fragment,
265 | uint16_t length )
266 | {
267 | assert( pBufferCursor != NULL );
268 | assert( *pBufferCursor != NULL );
269 | assert( fragment != NULL );
270 |
271 | ( void ) memcpy( ( void * ) *pBufferCursor,
272 | ( const void * ) fragment,
273 | ( size_t ) length );
274 |
275 | *pBufferCursor = &( ( *pBufferCursor )[ length ] );
276 | }
277 | /*-----------------------------------------------------------*/
278 |
279 | static FleetProvisioningStatus_t GetRegisterThingTopicCheckParams( const char * pTopicBuffer,
280 | FleetProvisioningFormat_t format,
281 | FleetProvisioningApiTopics_t topic,
282 | const char * pTemplateName,
283 | uint16_t templateNameLength,
284 | const uint16_t * pOutLength )
285 | {
286 | FleetProvisioningStatus_t ret = FleetProvisioningError;
287 |
288 | if( ( pTopicBuffer == NULL ) ||
289 | ( ( format != FleetProvisioningJson ) && ( format != FleetProvisioningCbor ) ) ||
290 | ( ( topic != FleetProvisioningPublish ) && ( topic != FleetProvisioningAccepted ) && ( topic != FleetProvisioningRejected ) ) ||
291 | ( pTemplateName == NULL ) ||
292 | ( templateNameLength == 0U ) ||
293 | ( templateNameLength > FP_TEMPLATENAME_MAX_LENGTH ) ||
294 | ( pOutLength == NULL ) )
295 | {
296 | ret = FleetProvisioningBadParameter;
297 |
298 | LogError( ( "Invalid input parameter. pTopicBuffer: %p, format: %d, topic: %d,"
299 | " pTemplateName: %p, templateNameLength: %u, pOutLength: %p.",
300 | ( const void * ) pTopicBuffer,
301 | ( int ) format,
302 | ( int ) topic,
303 | ( const void * ) pTemplateName,
304 | ( unsigned int ) templateNameLength,
305 | ( const void * ) pOutLength ) );
306 | }
307 | else
308 | {
309 | ret = FleetProvisioningSuccess;
310 | }
311 |
312 | return ret;
313 | }
314 | /*-----------------------------------------------------------*/
315 |
316 | static TopicSuffix_t parseTopicSuffix( const char * pRemainingTopic,
317 | uint16_t remainingLength )
318 | {
319 | TopicSuffix_t ret = TopicInvalidSuffix;
320 | FleetProvisioningStatus_t status = FleetProvisioningNoMatch;
321 | const char * pTopicCursor = pRemainingTopic;
322 | uint16_t cursorLength = remainingLength;
323 |
324 | assert( pRemainingTopic != NULL );
325 |
326 | /* Check if publish topic */
327 | if( cursorLength == 0U )
328 | {
329 | ret = TopicPublish;
330 | status = FleetProvisioningSuccess;
331 | }
332 |
333 | /* Check if accepted topic */
334 | if( status == FleetProvisioningNoMatch )
335 | {
336 | status = consumeIfMatch( &pTopicCursor,
337 | &cursorLength,
338 | FP_API_ACCEPTED_SUFFIX,
339 | FP_API_LENGTH_ACCEPTED_SUFFIX );
340 |
341 | if( status == FleetProvisioningSuccess )
342 | {
343 | if( cursorLength == 0U )
344 | {
345 | ret = TopicAccepted;
346 | }
347 | else
348 | {
349 | status = FleetProvisioningError;
350 | }
351 | }
352 | }
353 |
354 | /* Check if rejected topic */
355 | if( status == FleetProvisioningNoMatch )
356 | {
357 | status = consumeIfMatch( &pTopicCursor,
358 | &cursorLength,
359 | FP_API_REJECTED_SUFFIX,
360 | FP_API_LENGTH_REJECTED_SUFFIX );
361 |
362 | if( status == FleetProvisioningSuccess )
363 | {
364 | if( cursorLength == 0U )
365 | {
366 | ret = TopicRejected;
367 | }
368 | }
369 | }
370 |
371 | return ret;
372 | }
373 | /*-----------------------------------------------------------*/
374 |
375 | static TopicFormatSuffix_t parseTopicFormatSuffix( const char * pRemainingTopic,
376 | uint16_t remainingLength )
377 | {
378 | /* Table of JSON format and suffixes in same order as TopicSuffix_t. */
379 | static const TopicFormatSuffix_t jsonSuffixes[] =
380 | {
381 | TopicJsonPublish,
382 | TopicJsonAccepted,
383 | TopicJsonRejected,
384 | TopicInvalidFormatSuffix
385 | };
386 | /* Table of CBOR format and suffixes in same order as TopicSuffix_t. */
387 | static const TopicFormatSuffix_t cborSuffixes[] =
388 | {
389 | TopicCborPublish,
390 | TopicCborAccepted,
391 | TopicCborRejected,
392 | TopicInvalidFormatSuffix
393 | };
394 | TopicFormatSuffix_t ret = TopicInvalidFormatSuffix;
395 | TopicSuffix_t suffix = TopicInvalidSuffix;
396 | FleetProvisioningStatus_t status = FleetProvisioningNoMatch;
397 | const char * pTopicCursor = pRemainingTopic;
398 | uint16_t cursorLength = remainingLength;
399 |
400 | assert( pRemainingTopic != NULL );
401 |
402 | /* Check if JSON format */
403 | status = consumeIfMatch( &pTopicCursor,
404 | &cursorLength,
405 | FP_API_JSON_FORMAT,
406 | FP_API_LENGTH_JSON_FORMAT );
407 |
408 | if( status == FleetProvisioningSuccess )
409 | {
410 | /* Match suffix */
411 | suffix = parseTopicSuffix( pTopicCursor, cursorLength );
412 | ret = jsonSuffixes[ suffix ];
413 | }
414 |
415 | if( status == FleetProvisioningNoMatch )
416 | {
417 | /* Check if CBOR format */
418 | status = consumeIfMatch( &pTopicCursor,
419 | &cursorLength,
420 | FP_API_CBOR_FORMAT,
421 | FP_API_LENGTH_CBOR_FORMAT );
422 |
423 | if( status == FleetProvisioningSuccess )
424 | {
425 | /* Match suffix */
426 | suffix = parseTopicSuffix( pTopicCursor, cursorLength );
427 | ret = cborSuffixes[ suffix ];
428 | }
429 | }
430 |
431 | return ret;
432 | }
433 | /*-----------------------------------------------------------*/
434 |
435 | static FleetProvisioningTopic_t parseCreateCertificateFromCsrTopic( const char * pTopic,
436 | uint16_t topicLength )
437 | {
438 | /* Table of topics in the same order as TopicFormatSuffix_t. */
439 | static const FleetProvisioningTopic_t createCertificateFromCsrApi[] =
440 | {
441 | FleetProvJsonCreateCertFromCsrPublish,
442 | FleetProvJsonCreateCertFromCsrAccepted,
443 | FleetProvJsonCreateCertFromCsrRejected,
444 | FleetProvCborCreateCertFromCsrPublish,
445 | FleetProvCborCreateCertFromCsrAccepted,
446 | FleetProvCborCreateCertFromCsrRejected,
447 | FleetProvisioningInvalidTopic
448 | };
449 | FleetProvisioningTopic_t ret = FleetProvisioningInvalidTopic;
450 | FleetProvisioningStatus_t status = FleetProvisioningError;
451 | TopicFormatSuffix_t rest = TopicInvalidFormatSuffix;
452 | const char * pTopicCursor = pTopic;
453 | uint16_t cursorLength = topicLength;
454 |
455 | assert( pTopic != NULL );
456 |
457 | /* Check if prefix matches */
458 | status = consumeIfMatch( &pTopicCursor,
459 | &cursorLength,
460 | FP_CREATE_CERT_API_PREFIX,
461 | FP_CREATE_CERT_API_LENGTH_PREFIX );
462 |
463 | if( status == FleetProvisioningSuccess )
464 | {
465 | /* Match format and suffix */
466 | rest = parseTopicFormatSuffix( pTopicCursor, cursorLength );
467 | ret = createCertificateFromCsrApi[ rest ];
468 | }
469 |
470 | return ret;
471 | }
472 | /*-----------------------------------------------------------*/
473 |
474 | static FleetProvisioningTopic_t parseCreateKeysAndCertificateTopic( const char * pTopic,
475 | uint16_t topicLength )
476 | {
477 | /* Table of topics in the same order as TopicFormatSuffix_t. */
478 | static const FleetProvisioningTopic_t createKeysAndCertificateApi[] =
479 | {
480 | FleetProvJsonCreateKeysAndCertPublish,
481 | FleetProvJsonCreateKeysAndCertAccepted,
482 | FleetProvJsonCreateKeysAndCertRejected,
483 | FleetProvCborCreateKeysAndCertPublish,
484 | FleetProvCborCreateKeysAndCertAccepted,
485 | FleetProvCborCreateKeysAndCertRejected,
486 | FleetProvisioningInvalidTopic
487 | };
488 | FleetProvisioningTopic_t ret = FleetProvisioningInvalidTopic;
489 | FleetProvisioningStatus_t status = FleetProvisioningError;
490 | TopicFormatSuffix_t rest = TopicInvalidFormatSuffix;
491 | const char * pTopicCursor = pTopic;
492 | uint16_t cursorLength = topicLength;
493 |
494 | assert( pTopic != NULL );
495 |
496 | /* Check if prefix matches */
497 | status = consumeIfMatch( &pTopicCursor,
498 | &cursorLength,
499 | FP_CREATE_KEYS_API_PREFIX,
500 | FP_CREATE_KEYS_API_LENGTH_PREFIX );
501 |
502 | if( status == FleetProvisioningSuccess )
503 | {
504 | /* Match format and suffix */
505 | rest = parseTopicFormatSuffix( pTopicCursor, cursorLength );
506 | ret = createKeysAndCertificateApi[ rest ];
507 | }
508 |
509 | return ret;
510 | }
511 | /*-----------------------------------------------------------*/
512 |
513 | static FleetProvisioningTopic_t parseRegisterThingTopic( const char * pTopic,
514 | uint16_t topicLength )
515 | {
516 | /* Table of topics in the same order as TopicFormatSuffix_t. */
517 | static const FleetProvisioningTopic_t registerThingApi[] =
518 | {
519 | FleetProvJsonRegisterThingPublish,
520 | FleetProvJsonRegisterThingAccepted,
521 | FleetProvJsonRegisterThingRejected,
522 | FleetProvCborRegisterThingPublish,
523 | FleetProvCborRegisterThingAccepted,
524 | FleetProvCborRegisterThingRejected,
525 | FleetProvisioningInvalidTopic
526 | };
527 | FleetProvisioningTopic_t ret = FleetProvisioningInvalidTopic;
528 | FleetProvisioningStatus_t status = FleetProvisioningError;
529 | TopicFormatSuffix_t rest = TopicInvalidFormatSuffix;
530 | const char * pTopicCursor = pTopic;
531 | uint16_t cursorLength = topicLength;
532 |
533 | assert( pTopic != NULL );
534 |
535 | /* Check if prefix matches */
536 | status = consumeIfMatch( &pTopicCursor,
537 | &cursorLength,
538 | FP_REGISTER_API_PREFIX,
539 | FP_REGISTER_API_LENGTH_PREFIX );
540 |
541 | if( status == FleetProvisioningSuccess )
542 | {
543 | /* Skip template name */
544 | status = consumeTemplateName( &pTopicCursor,
545 | &cursorLength );
546 | }
547 |
548 | if( status == FleetProvisioningSuccess )
549 | {
550 | /* Check if bridge matches */
551 | status = consumeIfMatch( &pTopicCursor,
552 | &cursorLength,
553 | FP_REGISTER_API_BRIDGE,
554 | FP_REGISTER_API_LENGTH_BRIDGE );
555 | }
556 |
557 | if( status == FleetProvisioningSuccess )
558 | {
559 | /* Match format and suffix */
560 | rest = parseTopicFormatSuffix( pTopicCursor, cursorLength );
561 | ret = registerThingApi[ rest ];
562 | }
563 |
564 | return ret;
565 | }
566 | /*-----------------------------------------------------------*/
567 |
568 | static FleetProvisioningStatus_t consumeIfMatch( const char ** pBufferCursor,
569 | uint16_t * pRemainingLength,
570 | const char * matchString,
571 | uint16_t matchLength )
572 | {
573 | FleetProvisioningStatus_t status = FleetProvisioningError;
574 | int32_t cmpVal = -1;
575 |
576 | assert( pBufferCursor != NULL );
577 | assert( *pBufferCursor != NULL );
578 | assert( pRemainingLength != NULL );
579 | assert( matchString != NULL );
580 |
581 | if( *pRemainingLength < matchLength )
582 | {
583 | status = FleetProvisioningNoMatch;
584 | }
585 | else
586 | {
587 | cmpVal = strncmp( *pBufferCursor,
588 | matchString,
589 | ( size_t ) matchLength );
590 |
591 | if( cmpVal != 0 )
592 | {
593 | status = FleetProvisioningNoMatch;
594 | }
595 | else
596 | {
597 | status = FleetProvisioningSuccess;
598 | *pBufferCursor = &( ( *pBufferCursor )[ matchLength ] );
599 | *pRemainingLength -= matchLength;
600 | }
601 | }
602 |
603 | return status;
604 | }
605 | /*-----------------------------------------------------------*/
606 |
607 | static FleetProvisioningStatus_t consumeTemplateName( const char ** pTopicCursor,
608 | uint16_t * pRemainingLength )
609 | {
610 | FleetProvisioningStatus_t ret = FleetProvisioningNoMatch;
611 | uint16_t i = 0U;
612 |
613 | assert( pTopicCursor != NULL );
614 | assert( *pTopicCursor != NULL );
615 | assert( pRemainingLength != NULL );
616 |
617 | /* Find the first forward slash. It marks the end of the template name. */
618 | for( i = 0U; i < *pRemainingLength; i++ )
619 | {
620 | if( ( *pTopicCursor )[ i ] == '/' )
621 | {
622 | break;
623 | }
624 | }
625 |
626 | /* Zero length template name is not valid. */
627 | if( i > 0U )
628 | {
629 | ret = FleetProvisioningSuccess;
630 | *pTopicCursor = &( ( *pTopicCursor )[ i ] );
631 | *pRemainingLength -= i;
632 | }
633 |
634 | return ret;
635 | }
636 | /*-----------------------------------------------------------*/
637 |
638 | FleetProvisioningStatus_t FleetProvisioning_GetRegisterThingTopic( char * pTopicBuffer,
639 | uint16_t bufferLength,
640 | FleetProvisioningFormat_t format,
641 | FleetProvisioningApiTopics_t topic,
642 | const char * pTemplateName,
643 | uint16_t templateNameLength,
644 | uint16_t * pOutLength )
645 | {
646 | FleetProvisioningStatus_t status = FleetProvisioningError;
647 | uint16_t topicLength = 0U;
648 | char * pBufferCursor = pTopicBuffer;
649 |
650 | status = GetRegisterThingTopicCheckParams( pTopicBuffer,
651 | format,
652 | topic,
653 | pTemplateName,
654 | templateNameLength,
655 | pOutLength );
656 |
657 | if( status == FleetProvisioningSuccess )
658 | {
659 | topicLength = getRegisterThingTopicLength( templateNameLength, format, topic );
660 |
661 | if( bufferLength < topicLength )
662 | {
663 | status = FleetProvisioningBufferTooSmall;
664 |
665 | LogError( ( "The buffer is too small to hold the topic string. "
666 | "Provided buffer size: %u, Required buffer size: %u.",
667 | ( unsigned int ) bufferLength,
668 | ( unsigned int ) topicLength ) );
669 | }
670 | }
671 |
672 | if( status == FleetProvisioningSuccess )
673 | {
674 | /* At this point, it is certain that we have a large enough buffer to
675 | * write the topic string into. */
676 |
677 | /* Write prefix first. */
678 | writeTopicFragmentAndAdvance( &pBufferCursor,
679 | FP_REGISTER_API_PREFIX,
680 | FP_REGISTER_API_LENGTH_PREFIX );
681 |
682 | /* Write template name next. */
683 | writeTopicFragmentAndAdvance( &pBufferCursor,
684 | pTemplateName,
685 | templateNameLength );
686 |
687 | /* Write bridge next. */
688 | writeTopicFragmentAndAdvance( &pBufferCursor,
689 | FP_REGISTER_API_BRIDGE,
690 | FP_REGISTER_API_LENGTH_BRIDGE );
691 |
692 | /* Write report format. */
693 | if( format == FleetProvisioningJson )
694 | {
695 | writeTopicFragmentAndAdvance( &pBufferCursor,
696 | FP_API_JSON_FORMAT,
697 | FP_API_LENGTH_JSON_FORMAT );
698 | }
699 |
700 | if( format == FleetProvisioningCbor )
701 | {
702 | writeTopicFragmentAndAdvance( &pBufferCursor,
703 | FP_API_CBOR_FORMAT,
704 | FP_API_LENGTH_CBOR_FORMAT );
705 | }
706 |
707 | /* Write report suffix. */
708 | if( topic == FleetProvisioningAccepted )
709 | {
710 | writeTopicFragmentAndAdvance( &pBufferCursor,
711 | FP_API_ACCEPTED_SUFFIX,
712 | FP_API_LENGTH_ACCEPTED_SUFFIX );
713 | }
714 |
715 | if( topic == FleetProvisioningRejected )
716 | {
717 | writeTopicFragmentAndAdvance( &pBufferCursor,
718 | FP_API_REJECTED_SUFFIX,
719 | FP_API_LENGTH_REJECTED_SUFFIX );
720 | }
721 |
722 | *pOutLength = topicLength;
723 | }
724 |
725 | return status;
726 | }
727 | /*-----------------------------------------------------------*/
728 |
729 | FleetProvisioningStatus_t FleetProvisioning_MatchTopic( const char * pTopic,
730 | uint16_t topicLength,
731 | FleetProvisioningTopic_t * pOutApi )
732 | {
733 | FleetProvisioningStatus_t ret = FleetProvisioningNoMatch;
734 |
735 | if( ( pTopic == NULL ) || ( pOutApi == NULL ) )
736 | {
737 | ret = FleetProvisioningBadParameter;
738 | LogError( ( "Invalid input parameter. pTopic: %p, pOutApi: %p.",
739 | ( const void * ) pTopic,
740 | ( void * ) pOutApi ) );
741 | }
742 | else
743 | {
744 | *pOutApi = parseCreateCertificateFromCsrTopic( pTopic, topicLength );
745 |
746 | if( *pOutApi == FleetProvisioningInvalidTopic )
747 | {
748 | *pOutApi = parseCreateKeysAndCertificateTopic( pTopic, topicLength );
749 | }
750 |
751 | if( *pOutApi == FleetProvisioningInvalidTopic )
752 | {
753 | *pOutApi = parseRegisterThingTopic( pTopic, topicLength );
754 | }
755 |
756 | if( *pOutApi != FleetProvisioningInvalidTopic )
757 | {
758 | ret = FleetProvisioningSuccess;
759 | }
760 | }
761 |
762 | return ret;
763 | }
764 | /*-----------------------------------------------------------*/
765 |
--------------------------------------------------------------------------------
/source/include/fleet_provisioning.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AWS IoT Fleet Provisioning v1.2.1
3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | *
5 | * SPDX-License-Identifier: MIT
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | * this software and associated documentation files (the "Software"), to deal in
9 | * the Software without restriction, including without limitation the rights to
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | * the Software, and to permit persons to whom the Software is furnished to do so,
12 | * subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /**
26 | * @file fleet_provisioning.h
27 | * @brief Interface for the AWS IoT Fleet Provisioning Library.
28 | */
29 |
30 | #ifndef FLEET_PROVISIONING_H_
31 | #define FLEET_PROVISIONING_H_
32 |
33 | /* Standard includes. */
34 | #include
35 |
36 | /* *INDENT-OFF* */
37 | #ifdef __cplusplus
38 | extern "C" {
39 | #endif
40 | /* *INDENT-ON* */
41 |
42 | /* FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG allows building the Fleet
43 | * Provisioning library without a config file. If a config file is provided,
44 | * FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG macro must not be defined.
45 | */
46 | #ifndef FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG
47 | #include "fleet_provisioning_config.h"
48 | #endif
49 |
50 | /* Default config values. */
51 | #include "fleet_provisioning_config_defaults.h"
52 |
53 | /**
54 | * @ingroup fleet_provisioning_enum_types
55 | * @brief Return codes for Fleet Provisioning APIs.
56 | */
57 | typedef enum
58 | {
59 | FleetProvisioningError = 0,
60 | FleetProvisioningSuccess,
61 | FleetProvisioningNoMatch,
62 | FleetProvisioningBadParameter,
63 | FleetProvisioningBufferTooSmall
64 | } FleetProvisioningStatus_t;
65 |
66 | /**
67 | * @ingroup fleet_provisioning_enum_types
68 | * @brief Fleet Provisioning topic values.
69 | */
70 | typedef enum
71 | {
72 | FleetProvisioningInvalidTopic = 0,
73 | FleetProvJsonCreateCertFromCsrPublish,
74 | FleetProvJsonCreateCertFromCsrAccepted,
75 | FleetProvJsonCreateCertFromCsrRejected,
76 | FleetProvJsonCreateKeysAndCertPublish,
77 | FleetProvJsonCreateKeysAndCertAccepted,
78 | FleetProvJsonCreateKeysAndCertRejected,
79 | FleetProvJsonRegisterThingPublish,
80 | FleetProvJsonRegisterThingAccepted,
81 | FleetProvJsonRegisterThingRejected,
82 | FleetProvCborCreateCertFromCsrPublish,
83 | FleetProvCborCreateCertFromCsrAccepted,
84 | FleetProvCborCreateCertFromCsrRejected,
85 | FleetProvCborCreateKeysAndCertPublish,
86 | FleetProvCborCreateKeysAndCertAccepted,
87 | FleetProvCborCreateKeysAndCertRejected,
88 | FleetProvCborRegisterThingPublish,
89 | FleetProvCborRegisterThingAccepted,
90 | FleetProvCborRegisterThingRejected
91 | } FleetProvisioningTopic_t;
92 |
93 | /**
94 | * @ingroup fleet_provisioning_enum_types
95 | * @brief Topics for each Fleet Provisioning APIs.
96 | */
97 | typedef enum
98 | {
99 | FleetProvisioningPublish,
100 | FleetProvisioningAccepted,
101 | FleetProvisioningRejected
102 | } FleetProvisioningApiTopics_t;
103 |
104 | /**
105 | * @ingroup fleet_provisioning_enum_types
106 | * @brief Message format for Fleet Provisioning APIs.
107 | */
108 | typedef enum
109 | {
110 | FleetProvisioningJson,
111 | FleetProvisioningCbor
112 | } FleetProvisioningFormat_t;
113 |
114 | /*-----------------------------------------------------------*/
115 |
116 | /**
117 | * @ingroup fleet_provisioning_constants
118 | * @brief Maximum length of a thing's name as permitted by AWS IoT Core.
119 | */
120 | #define FP_TEMPLATENAME_MAX_LENGTH 36U
121 |
122 | /*-----------------------------------------------------------*/
123 |
124 | /**
125 | * @cond DOXYGEN_IGNORE
126 | * Doxygen should ignore these macros as they are private.
127 | */
128 |
129 | #define FP_CREATE_CERT_API_PREFIX "$aws/certificates/create-from-csr/"
130 | #define FP_CREATE_CERT_API_LENGTH_PREFIX ( ( uint16_t ) ( sizeof( FP_CREATE_CERT_API_PREFIX ) - 1U ) )
131 |
132 | #define FP_CREATE_KEYS_API_PREFIX "$aws/certificates/create/"
133 | #define FP_CREATE_KEYS_API_LENGTH_PREFIX ( ( uint16_t ) ( sizeof( FP_CREATE_KEYS_API_PREFIX ) - 1U ) )
134 |
135 | #define FP_REGISTER_API_PREFIX "$aws/provisioning-templates/"
136 | #define FP_REGISTER_API_LENGTH_PREFIX ( ( uint16_t ) ( sizeof( FP_REGISTER_API_PREFIX ) - 1U ) )
137 |
138 | #define FP_REGISTER_API_BRIDGE "/provision/"
139 | #define FP_REGISTER_API_LENGTH_BRIDGE ( ( uint16_t ) ( sizeof( FP_REGISTER_API_BRIDGE ) - 1U ) )
140 |
141 | #define FP_API_JSON_FORMAT "json"
142 | #define FP_API_LENGTH_JSON_FORMAT ( ( uint16_t ) ( sizeof( FP_API_JSON_FORMAT ) - 1U ) )
143 |
144 | #define FP_API_CBOR_FORMAT "cbor"
145 | #define FP_API_LENGTH_CBOR_FORMAT ( ( uint16_t ) ( sizeof( FP_API_CBOR_FORMAT ) - 1U ) )
146 |
147 | #define FP_API_ACCEPTED_SUFFIX "/accepted"
148 | #define FP_API_LENGTH_ACCEPTED_SUFFIX ( ( uint16_t ) ( sizeof( FP_API_ACCEPTED_SUFFIX ) - 1U ) )
149 |
150 | #define FP_API_REJECTED_SUFFIX "/rejected"
151 | #define FP_API_LENGTH_REJECTED_SUFFIX ( ( uint16_t ) ( sizeof( FP_API_REJECTED_SUFFIX ) - 1U ) )
152 |
153 | /** @endcond */
154 |
155 | /*-----------------------------------------------------------*/
156 |
157 | /* Fleet Provisioning CreateCertificateFromCSR macros */
158 |
159 | /**
160 | * @brief Topic string for publishing a JSON CreateCertificateFromCSR request.
161 | */
162 | #define FP_JSON_CREATE_CERT_PUBLISH_TOPIC \
163 | ( FP_CREATE_CERT_API_PREFIX \
164 | FP_API_JSON_FORMAT )
165 |
166 | /**
167 | * @brief Topic string for getting a JSON CreateCertificateFromCSR accepted response.
168 | */
169 | #define FP_JSON_CREATE_CERT_ACCEPTED_TOPIC \
170 | ( FP_CREATE_CERT_API_PREFIX \
171 | FP_API_JSON_FORMAT \
172 | FP_API_ACCEPTED_SUFFIX )
173 |
174 | /**
175 | * @brief Topic string for getting a JSON CreateCertificateFromCSR error response.
176 | */
177 | #define FP_JSON_CREATE_CERT_REJECTED_TOPIC \
178 | ( FP_CREATE_CERT_API_PREFIX \
179 | FP_API_JSON_FORMAT \
180 | FP_API_REJECTED_SUFFIX )
181 |
182 | /**
183 | * @brief Topic string for publishing a CBOR CreateCertificateFromCSR request.
184 | */
185 | #define FP_CBOR_CREATE_CERT_PUBLISH_TOPIC \
186 | ( FP_CREATE_CERT_API_PREFIX \
187 | FP_API_CBOR_FORMAT )
188 |
189 | /**
190 | * @brief Topic string for getting a CBOR CreateCertificateFromCSR accepted response.
191 | */
192 | #define FP_CBOR_CREATE_CERT_ACCEPTED_TOPIC \
193 | ( FP_CREATE_CERT_API_PREFIX \
194 | FP_API_CBOR_FORMAT \
195 | FP_API_ACCEPTED_SUFFIX )
196 |
197 | /**
198 | * @brief Topic string for getting a CBOR CreateCertificateFromCSR error response.
199 | */
200 | #define FP_CBOR_CREATE_CERT_REJECTED_TOPIC \
201 | ( FP_CREATE_CERT_API_PREFIX \
202 | FP_API_CBOR_FORMAT \
203 | FP_API_REJECTED_SUFFIX )
204 |
205 | /**
206 | * @brief Length of topic string for publishing a JSON CreateCertificateFromCSR request.
207 | */
208 | #define FP_JSON_CREATE_CERT_PUBLISH_LENGTH \
209 | ( ( uint16_t ) ( sizeof( FP_JSON_CREATE_CERT_PUBLISH_TOPIC ) - 1U ) )
210 |
211 | /**
212 | * @brief Length of topic string for getting a JSON CreateCertificateFromCSR accepted response.
213 | */
214 | #define FP_JSON_CREATE_CERT_ACCEPTED_LENGTH \
215 | ( ( uint16_t ) ( sizeof( FP_JSON_CREATE_CERT_ACCEPTED_TOPIC ) - 1U ) )
216 |
217 | /**
218 | * @brief Length of topic string for getting a JSON CreateCertificateFromCSR error response.
219 | */
220 | #define FP_JSON_CREATE_CERT_REJECTED_LENGTH \
221 | ( ( uint16_t ) ( sizeof( FP_JSON_CREATE_CERT_REJECTED_TOPIC ) - 1U ) )
222 |
223 | /**
224 | * @brief Length of topic string for publishing a CBOR CreateCertificateFromCSR request.
225 | */
226 | #define FP_CBOR_CREATE_CERT_PUBLISH_LENGTH \
227 | ( ( uint16_t ) ( sizeof( FP_CBOR_CREATE_CERT_PUBLISH_TOPIC ) - 1U ) )
228 |
229 | /**
230 | * @brief Length of topic string for getting a CBOR CreateCertificateFromCSR accepted response.
231 | */
232 | #define FP_CBOR_CREATE_CERT_ACCEPTED_LENGTH \
233 | ( ( uint16_t ) ( sizeof( FP_CBOR_CREATE_CERT_ACCEPTED_TOPIC ) - 1U ) )
234 |
235 | /**
236 | * @brief Length of topic string for getting a CBOR CreateCertificateFromCSR error response.
237 | */
238 | #define FP_CBOR_CREATE_CERT_REJECTED_LENGTH \
239 | ( ( uint16_t ) ( sizeof( FP_CBOR_CREATE_CERT_REJECTED_TOPIC ) - 1U ) )
240 |
241 | /*-----------------------------------------------------------*/
242 |
243 | /* Fleet Provisioning CreateKeysAndCertificate macros */
244 |
245 | /**
246 | * @brief Topic string for publishing a JSON CreateKeysAndCertificate request.
247 | */
248 | #define FP_JSON_CREATE_KEYS_PUBLISH_TOPIC \
249 | ( FP_CREATE_KEYS_API_PREFIX \
250 | FP_API_JSON_FORMAT )
251 |
252 | /**
253 | * @brief Topic string for getting a JSON CreateKeysAndCertificate accepted response.
254 | */
255 | #define FP_JSON_CREATE_KEYS_ACCEPTED_TOPIC \
256 | ( FP_CREATE_KEYS_API_PREFIX \
257 | FP_API_JSON_FORMAT \
258 | FP_API_ACCEPTED_SUFFIX )
259 |
260 | /**
261 | * @brief Topic string for getting a JSON CreateKeysAndCertificate error
262 | * response.
263 | */
264 | #define FP_JSON_CREATE_KEYS_REJECTED_TOPIC \
265 | ( FP_CREATE_KEYS_API_PREFIX \
266 | FP_API_JSON_FORMAT \
267 | FP_API_REJECTED_SUFFIX )
268 |
269 | /**
270 | * @brief Topic string for publishing a CBOR CreateKeysAndCertificate request.
271 | */
272 | #define FP_CBOR_CREATE_KEYS_PUBLISH_TOPIC \
273 | ( FP_CREATE_KEYS_API_PREFIX \
274 | FP_API_CBOR_FORMAT )
275 |
276 | /**
277 | * @brief Topic string for getting a CBOR CreateKeysAndCertificate accepted response.
278 | */
279 | #define FP_CBOR_CREATE_KEYS_ACCEPTED_TOPIC \
280 | ( FP_CREATE_KEYS_API_PREFIX \
281 | FP_API_CBOR_FORMAT \
282 | FP_API_ACCEPTED_SUFFIX )
283 |
284 | /**
285 | * @brief Topic string for getting a CBOR CreateKeysAndCertificate error
286 | * response.
287 | */
288 | #define FP_CBOR_CREATE_KEYS_REJECTED_TOPIC \
289 | ( FP_CREATE_KEYS_API_PREFIX \
290 | FP_API_CBOR_FORMAT \
291 | FP_API_REJECTED_SUFFIX )
292 |
293 | /**
294 | * @brief Length of topic string for publishing a JSON CreateKeysAndCertificate request.
295 | */
296 | #define FP_JSON_CREATE_KEYS_PUBLISH_LENGTH \
297 | ( ( uint16_t ) ( sizeof( FP_JSON_CREATE_KEYS_PUBLISH_TOPIC ) - 1U ) )
298 |
299 | /**
300 | * @brief Length of topic string for getting a JSON CreateKeysAndCertificate accepted response.
301 | */
302 | #define FP_JSON_CREATE_KEYS_ACCEPTED_LENGTH \
303 | ( ( uint16_t ) ( sizeof( FP_JSON_CREATE_KEYS_ACCEPTED_TOPIC ) - 1U ) )
304 |
305 | /**
306 | * @brief Length of topic string for getting a JSON CreateKeysAndCertificate error response.
307 | */
308 | #define FP_JSON_CREATE_KEYS_REJECTED_LENGTH \
309 | ( ( uint16_t ) ( sizeof( FP_JSON_CREATE_KEYS_REJECTED_TOPIC ) - 1U ) )
310 |
311 | /**
312 | * @brief Length of topic string for publishing a CBOR CreateKeysAndCertificate request.
313 | */
314 | #define FP_CBOR_CREATE_KEYS_PUBLISH_LENGTH \
315 | ( ( uint16_t ) ( sizeof( FP_CBOR_CREATE_KEYS_PUBLISH_TOPIC ) - 1U ) )
316 |
317 | /**
318 | * @brief Length of topic string for getting a CBOR CreateKeysAndCertificate accepted response.
319 | */
320 | #define FP_CBOR_CREATE_KEYS_ACCEPTED_LENGTH \
321 | ( ( uint16_t ) ( sizeof( FP_CBOR_CREATE_KEYS_ACCEPTED_TOPIC ) - 1U ) )
322 |
323 | /**
324 | * @brief Length of topic string for getting a CBOR CreateKeysAndCertificate error response.
325 | */
326 | #define FP_CBOR_CREATE_KEYS_REJECTED_LENGTH \
327 | ( ( uint16_t ) ( sizeof( FP_CBOR_CREATE_KEYS_REJECTED_TOPIC ) - 1U ) )
328 |
329 | /*-----------------------------------------------------------*/
330 |
331 | /* Fleet Provisioning RegisterThing macros */
332 |
333 |
334 | /**
335 | * @brief Topic string for publishing a JSON RegisterThing request.
336 | *
337 | * This macro should be used when the provisioning template name is known at
338 | * compile time. If the provisioning template name is not known at compile time,
339 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
340 | *
341 | * @param templateName The name of the provisioning template to use.
342 | */
343 | #define FP_JSON_REGISTER_PUBLISH_TOPIC( templateName ) \
344 | ( FP_REGISTER_API_PREFIX \
345 | templateName \
346 | FP_REGISTER_API_BRIDGE \
347 | FP_API_JSON_FORMAT )
348 |
349 | /**
350 | * @brief Topic string for getting a JSON RegisterThing accepted response.
351 | *
352 | * This macro should be used when the provisioning template name is known at
353 | * compile time. If the provisioning template name is not known at compile time,
354 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
355 | *
356 | * @param templateName The name of the provisioning template to use.
357 | */
358 | #define FP_JSON_REGISTER_ACCEPTED_TOPIC( templateName ) \
359 | ( FP_REGISTER_API_PREFIX \
360 | templateName \
361 | FP_REGISTER_API_BRIDGE \
362 | FP_API_JSON_FORMAT \
363 | FP_API_ACCEPTED_SUFFIX )
364 |
365 | /**
366 | * @brief Topic string for getting a JSON RegisterThing error response.
367 | *
368 | * This macro should be used when the provisioning template name is known at
369 | * compile time. If the provisioning template name is not known at compile time,
370 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
371 | *
372 | * @param templateName The name of the provisioning template to use.
373 | */
374 | #define FP_JSON_REGISTER_REJECTED_TOPIC( templateName ) \
375 | ( FP_REGISTER_API_PREFIX \
376 | templateName \
377 | FP_REGISTER_API_BRIDGE \
378 | FP_API_JSON_FORMAT \
379 | FP_API_REJECTED_SUFFIX )
380 |
381 | /**
382 | * @brief Topic string for publishing a CBOR RegisterThing request.
383 | *
384 | * This macro should be used when the provisioning template name is known at
385 | * compile time. If the provisioning template name is not known at compile time,
386 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
387 | *
388 | * @param templateName The name of the provisioning template to use.
389 | */
390 | #define FP_CBOR_REGISTER_PUBLISH_TOPIC( templateName ) \
391 | ( FP_REGISTER_API_PREFIX \
392 | templateName \
393 | FP_REGISTER_API_BRIDGE \
394 | FP_API_CBOR_FORMAT )
395 |
396 | /**
397 | * @brief Topic string for getting a CBOR RegisterThing accepted response.
398 | *
399 | * This macro should be used when the provisioning template name is known at
400 | * compile time. If the provisioning template name is not known at compile time,
401 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
402 | *
403 | * @param templateName The name of the provisioning template to use.
404 | */
405 | #define FP_CBOR_REGISTER_ACCEPTED_TOPIC( templateName ) \
406 | ( FP_REGISTER_API_PREFIX \
407 | templateName \
408 | FP_REGISTER_API_BRIDGE \
409 | FP_API_CBOR_FORMAT \
410 | FP_API_ACCEPTED_SUFFIX )
411 |
412 | /**
413 | * @brief Topic string for getting a CBOR RegisterThing error response.
414 | *
415 | * This macro should be used when the provisioning template name is known at
416 | * compile time. If the provisioning template name is not known at compile time,
417 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
418 | *
419 | * @param templateName The name of the provisioning template to use.
420 | */
421 | #define FP_CBOR_REGISTER_REJECTED_TOPIC( templateName ) \
422 | ( FP_REGISTER_API_PREFIX \
423 | templateName \
424 | FP_REGISTER_API_BRIDGE \
425 | FP_API_CBOR_FORMAT \
426 | FP_API_REJECTED_SUFFIX )
427 |
428 | /**
429 | * @brief Length of topic string for publishing a JSON RegisterThing request.
430 | *
431 | * This macro should be used when the provisioning template name is known at
432 | * compile time. If the provisioning template name is not known at compile time,
433 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
434 | *
435 | * @param templateNameLength The length of the provisioning template name.
436 | */
437 | #define FP_JSON_REGISTER_PUBLISH_LENGTH( templateNameLength ) \
438 | ( FP_REGISTER_API_LENGTH_PREFIX + \
439 | ( templateNameLength ) + \
440 | FP_REGISTER_API_LENGTH_BRIDGE + \
441 | FP_API_LENGTH_JSON_FORMAT )
442 |
443 | /**
444 | * @brief Length of topic string for getting a JSON RegisterThing accepted response.
445 | *
446 | * This macro should be used when the provisioning template name is known at
447 | * compile time. If the provisioning template name is not known at compile time,
448 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
449 | *
450 | * @param templateNameLength The length of the provisioning template name.
451 | */
452 | #define FP_JSON_REGISTER_ACCEPTED_LENGTH( templateNameLength ) \
453 | ( FP_REGISTER_API_LENGTH_PREFIX + \
454 | ( templateNameLength ) + \
455 | FP_REGISTER_API_LENGTH_BRIDGE + \
456 | FP_API_LENGTH_JSON_FORMAT + \
457 | FP_API_LENGTH_ACCEPTED_SUFFIX )
458 |
459 | /**
460 | * @brief Length of topic string for getting a JSON RegisterThing error response.
461 | *
462 | * This macro should be used when the provisioning template name is known at
463 | * compile time. If the provisioning template name is not known at compile time,
464 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
465 | *
466 | * @param templateNameLength The length of the provisioning template name.
467 | */
468 | #define FP_JSON_REGISTER_REJECTED_LENGTH( templateNameLength ) \
469 | ( FP_REGISTER_API_LENGTH_PREFIX + \
470 | ( templateNameLength ) + \
471 | FP_REGISTER_API_LENGTH_BRIDGE + \
472 | FP_API_LENGTH_JSON_FORMAT + \
473 | FP_API_LENGTH_REJECTED_SUFFIX )
474 |
475 | /**
476 | * @brief Length of topic string for publishing a CBOR RegisterThing request.
477 | *
478 | * This macro should be used when the provisioning template name is known at
479 | * compile time. If the provisioning template name is not known at compile time,
480 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
481 | *
482 | * @param templateNameLength The length of the provisioning template name.
483 | */
484 | #define FP_CBOR_REGISTER_PUBLISH_LENGTH( templateNameLength ) \
485 | ( FP_REGISTER_API_LENGTH_PREFIX + \
486 | ( templateNameLength ) + \
487 | FP_REGISTER_API_LENGTH_BRIDGE + \
488 | FP_API_LENGTH_CBOR_FORMAT )
489 |
490 | /**
491 | * @brief Length of topic string for getting a CBOR RegisterThing accepted response.
492 | *
493 | * This macro should be used when the provisioning template name is known at
494 | * compile time. If the provisioning template name is not known at compile time,
495 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
496 | *
497 | * @param templateNameLength The length of the provisioning template name.
498 | */
499 | #define FP_CBOR_REGISTER_ACCEPTED_LENGTH( templateNameLength ) \
500 | ( FP_REGISTER_API_LENGTH_PREFIX + \
501 | ( templateNameLength ) + \
502 | FP_REGISTER_API_LENGTH_BRIDGE + \
503 | FP_API_LENGTH_CBOR_FORMAT + \
504 | FP_API_LENGTH_ACCEPTED_SUFFIX )
505 |
506 | /**
507 | * @brief Length of topic string for getting a CBOR RegisterThing error response.
508 | *
509 | * This macro should be used when the provisioning template name is known at
510 | * compile time. If the provisioning template name is not known at compile time,
511 | * the #FleetProvisioning_GetRegisterThingTopic API should be used instead.
512 | *
513 | * @param templateNameLength The length of the provisioning template name.
514 | */
515 | #define FP_CBOR_REGISTER_REJECTED_LENGTH( templateNameLength ) \
516 | ( FP_REGISTER_API_LENGTH_PREFIX + \
517 | ( templateNameLength ) + \
518 | FP_REGISTER_API_LENGTH_BRIDGE + \
519 | FP_API_LENGTH_CBOR_FORMAT + \
520 | FP_API_LENGTH_REJECTED_SUFFIX )
521 |
522 | /*-----------------------------------------------------------*/
523 |
524 | /* Key names for Fleet Provisioning MQTT API JSON/CBOR payloads. */
525 |
526 | /**
527 | * @brief Key for the PEM-encoded certificate signing request in the
528 | * CreateCertificateFromCSR request payload.
529 | */
530 | #define FP_API_CSR_KEY "certificateSigningRequest"
531 |
532 | /**
533 | * @brief Key for the certificate ownership token in the
534 | * CreateCertificateFromCSR and CreateKeysAndCertificate response payloads, and
535 | * the RegisterThing request payload.
536 | */
537 | #define FP_API_OWNERSHIP_TOKEN_KEY "certificateOwnershipToken"
538 |
539 | /**
540 | * @brief Key for the certificate ID in the CreateCertificateFromCSR and
541 | * CreateKeysAndCertificate response payloads.
542 | */
543 | #define FP_API_CERTIFICATE_ID_KEY "certificateId"
544 |
545 | /**
546 | * @brief Key for the PEM-encoded certificate in the CreateCertificateFromCSR
547 | * and CreateKeysAndCertificate response payloads.
548 | */
549 | #define FP_API_CERTIFICATE_PEM_KEY "certificatePem"
550 |
551 | /**
552 | * @brief Key for the private key in the CreateKeysAndCertificate response
553 | * payload.
554 | */
555 | #define FP_API_PRIVATE_KEY_KEY "privateKey"
556 |
557 | /**
558 | * @brief Key for the optional parameters in the RegisterThing request payload.
559 | */
560 | #define FP_API_PARAMETERS_KEY "parameters"
561 |
562 | /**
563 | * @brief Key for the template-defined device configuration in the
564 | * RegisterThing response payload.
565 | */
566 | #define FP_API_DEVICE_CONFIG_KEY "deviceConfiguration"
567 |
568 | /**
569 | * @brief Key for the name of the created AWS IoT Thing in the RegisterThing
570 | * response payload.
571 | */
572 | #define FP_API_THING_NAME_KEY "thingName"
573 |
574 | /**
575 | * @brief Key for the status code in Fleet Provisioning error response
576 | * payloads.
577 | */
578 | #define FP_API_STATUS_CODE_KEY "statusCode"
579 |
580 | /**
581 | * @brief Key for the error code in Fleet Provisioning error response payloads.
582 | */
583 | #define FP_API_ERROR_CODE_KEY "errorCode"
584 |
585 | /**
586 | * @brief Key for the error message in Fleet Provisioning error response
587 | * payloads.
588 | */
589 | #define FP_API_ERROR_MESSAGE_KEY "errorMessage"
590 |
591 | /*-----------------------------------------------------------*/
592 |
593 | /**
594 | * @brief Populate the topic string for a Fleet Provisioning RegisterThing topic.
595 | *
596 | * @param[out] pTopicBuffer The buffer to write the topic string into.
597 | * @param[in] bufferLength The length of @p pTopicBuffer.
598 | * @param[in] format The desired RegisterThing format.
599 | * @param[in] topic The desired RegisterThing topic.
600 | * @param[in] pTemplateName The name of the provisioning template configured
601 | * with AWS IoT.
602 | * @param[in] templateNameLength The length of the provisioning template name.
603 | * @param[out] pOutLength The length of the topic string written to the buffer.
604 | *
605 | * @return FleetProvisioningSuccess if the topic string is written to the buffer;
606 | * FleetProvisioningBadParameter if invalid parameters, such as non-RegisterThing topics, are passed;
607 | * FleetProvisioningBufferTooSmall if the buffer cannot hold the full topic string.
608 | *
609 | * example
610 | * @code{c}
611 | *
612 | * // The following example shows how to use the FleetProvisioning_GetRegisterThingTopic
613 | * // function to generate a topic string for getting an accepted response for
614 | * // a JSON RegisterThing request.
615 | *
616 | * #define TOPIC_BUFFER_LENGTH ( 256u )
617 | *
618 | * // In order to use the AWS IoT Fleet Provisioning service, there must be a
619 | * // provisioning template registered with AWS IoT Core.
620 | * // This example assumes that the template is named "template_name".
621 | * #define TEMPLATE_NAME "template_name"
622 | * #define TEMPLATE_NAME_LENGTH ( ( uint16_t ) ( sizeof( TEMPLATE_NAME ) - 1U )
623 | * char pTopicbuffer[ TOPIC_BUFFER_LENGTH ] = { 0 };
624 | * uint16_t topicLength = 0;
625 | * FleetProvisioningStatus_t status = FleetProvisioningError;
626 | *
627 | * status = FleetProvisioning_GetRegisterThingTopic( pTopicBuffer,
628 | * TOPIC_BUFFER_LENGTH,
629 | * FleetProvisioningJson,
630 | * FleetProvisioningAccepted,
631 | * TEMPLATE_NAME,
632 | * TEMPLATE_NAME_LENGTH,
633 | * &( topiclength ) );
634 | *
635 | * if( status == FleetProvisioningSuccess )
636 | * {
637 | * // The buffer pTopicBuffer contains the topic string of length
638 | * // topicLength for getting a response for an accepted JSON RegisterThing
639 | * // request. Subscribe to this topic using an MQTT library of your choice.
640 | * }
641 | * @endcode
642 | */
643 | /* @[declare_fleet_provisioning_getregisterthingtopic] */
644 | FleetProvisioningStatus_t FleetProvisioning_GetRegisterThingTopic( char * pTopicBuffer,
645 | uint16_t bufferLength,
646 | FleetProvisioningFormat_t format,
647 | FleetProvisioningApiTopics_t topic,
648 | const char * pTemplateName,
649 | uint16_t templateNameLength,
650 | uint16_t * pOutLength );
651 | /* @[declare_fleet_provisioning_getregisterthingtopic] */
652 |
653 | /*-----------------------------------------------------------*/
654 |
655 | /**
656 | * @brief Check if the given topic is one of the Fleet Provisioning topics.
657 | *
658 | * The function outputs which API the topic is for.
659 | *
660 | * @param[in] pTopic The topic string to check.
661 | * @param[in] topicLength The length of the topic string.
662 | * @param[out] pOutApi The Fleet Provisioning topic API value.
663 | *
664 | * @return FleetProvisioningSuccess if the topic is one of the Fleet Provisioning topics;
665 | * FleetProvisioningBadParameter if invalid parameters are passed;
666 | * FleetProvisioningNoMatch if the topic is NOT one of the Fleet Provisioning topics (parameter
667 | * pOutApi gets FleetProvisioningInvalidTopic).
668 | *
669 | * Example
670 | * @code{c}
671 | *
672 | * // The following example shows how to use the FleetProvisioning_MatchTopic
673 | * // function to check if an incoming MQTT publish message is a Fleet
674 | * // Provisioning message.
675 | *
676 | * FleetProvisioningTopic_t api;
677 | * FleetProvisioningStatus_t status = FleetProvisioningError;
678 | *
679 | * // pTopic and topicLength are the topic string and length of the topic on
680 | * // which the publish message is received. These are usually provided by the
681 | * // MQTT library used.
682 | * status = FleetProvisioning_MatchTopic( pTopic
683 | * topicLength,
684 | * &( api ) );
685 | *
686 | * if( status == FleetProvisioningSuccess )
687 | * {
688 | * if( api == FleetProvJsonCreateCertFromCsrAccepted )
689 | * {
690 | * // The published JSON request was accepted and completed by the AWS
691 | * // IoT Fleet Provisioning service. You can parse the response using
692 | * // your choice of JSON parser get the certificate, ID, and ownership
693 | * // token.
694 | * }
695 | * else if( api == FleetProvJsonCreateCertFromCsrRejected )
696 | * {
697 | * // The published JSON request was rejected by the AWS IoT Fleet
698 | * // Provisioning service.
699 | * }
700 | * else
701 | * {
702 | * // Unexpected response.
703 | * }
704 | * }
705 | * @endcode
706 | */
707 | /* @[declare_fleet_provisioning_matchtopic] */
708 | FleetProvisioningStatus_t FleetProvisioning_MatchTopic( const char * pTopic,
709 | uint16_t topicLength,
710 | FleetProvisioningTopic_t * pOutApi );
711 | /* @[declare_fleet_provisioning_matchtopic] */
712 |
713 | /*-----------------------------------------------------------*/
714 |
715 | /* *INDENT-OFF* */
716 | #ifdef __cplusplus
717 | }
718 | #endif
719 | /* *INDENT-ON* */
720 |
721 | #endif /* FLEET_PROVISIONING_H_ */
722 |
--------------------------------------------------------------------------------
/source/include/fleet_provisioning_config_defaults.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AWS IoT Fleet Provisioning v1.2.1
3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | *
5 | * SPDX-License-Identifier: MIT
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | * this software and associated documentation files (the "Software"), to deal in
9 | * the Software without restriction, including without limitation the rights to
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | * the Software, and to permit persons to whom the Software is furnished to do so,
12 | * subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /**
26 | * @file fleet_provisioning_config_defaults.h
27 | * @brief Default config values for the AWS IoT Fleet Provisioning Library.
28 | */
29 |
30 | #ifndef FLEET_PROVISIONING_CONFIG_DEFAULTS_H_
31 | #define FLEET_PROVISIONING_CONFIG_DEFAULTS_H_
32 |
33 | /* The macro definition for FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG is for
34 | * Doxygen documentation only. */
35 |
36 | /**
37 | * @brief Define this macro to build the AWS IoT Fleet Provisioning Library
38 | * without the custom config file fleet_provisioning_config.h.
39 | *
40 | * Without the custom config, the the AWS IoT Fleet Provisioning Library builds
41 | * with default values of config macros defined in the
42 | * fleet_provisioning_config_defaults.h file.
43 | *
44 | * If a custom config file is provided, then
45 | * FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG must not be defined.
46 | *
47 | * Default value: FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG is
48 | * not defined by default and the library expects a
49 | * fleet_provisioning_config.h file.
50 | */
51 | #ifdef DOXYGEN
52 | #define FLEET_PROVISIONING_DO_NOT_USE_CUSTOM_CONFIG
53 | #endif
54 |
55 | /**
56 | * @brief Macro used in the Fleet Provisioning library to log error messages.
57 | *
58 | * To enable error logging, this macro should be mapped to an
59 | * application-specific logging implementation.
60 | *
61 | * @note This logging macro is called in the Fleet Provisioning library with
62 | * parameters wrapped in double parentheses to be ISO C89/C90 standard
63 | * compliant. For a reference POSIX implementation of the logging macros, refer
64 | * to the fleet_provisioning_config.h file, and the logging-stack in demos
65 | * folder of the [AWS IoT Embedded C SDK
66 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
67 | *
68 | * Default value: Error logs are turned off, and no code is generated for
69 | * calls to the macro in the Fleet Provisioning library on compilation.
70 | */
71 | #ifndef LogError
72 | #define LogError( message )
73 | #endif
74 |
75 | /**
76 | * @brief Macro used in the Fleet Provisioning library to log warning messages.
77 | *
78 | * To enable warning logging, this macro should be mapped to an
79 | * application-specific logging implementation.
80 | *
81 | * @note This logging macro is called in the Fleet Provisioning library with
82 | * parameters wrapped in double parentheses to be ISO C89/C90 standard
83 | * compliant. For a reference POSIX implementation of the logging macros, refer
84 | * to the fleet_provisioning_config.h file, and the logging-stack in demos
85 | * folder of the [AWS IoT Embedded C SDK
86 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
87 | *
88 | * Default value: Warning logs are turned off, and no code is generated
89 | * for calls to the macro in the Fleet Provisioning library on compilation.
90 | */
91 | #ifndef LogWarn
92 | #define LogWarn( message )
93 | #endif
94 |
95 | /**
96 | * @brief Macro used in the Fleet Provisioning library to log info messages.
97 | *
98 | * To enable info logging, this macro should be mapped to an
99 | * application-specific logging implementation.
100 | *
101 | * @note This logging macro is called in the Fleet Provisioning library with
102 | * parameters wrapped in double parentheses to be ISO C89/C90 standard
103 | * compliant. For a reference POSIX implementation of the logging macros, refer
104 | * to the fleet_provisioning_config.h file, and the logging-stack in demos
105 | * folder of the [AWS IoT Embedded C SDK
106 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
107 | *
108 | * Default value: Info logs are turned off, and no code is generated for
109 | * calls to the macro in the Fleet Provisioning library on compilation.
110 | */
111 | #ifndef LogInfo
112 | #define LogInfo( message )
113 | #endif
114 |
115 | /**
116 | * @brief Macro used in the Fleet Provisioning library to log debug messages.
117 | *
118 | * To enable debug logging, this macro should be mapped to an
119 | * application-specific logging implementation.
120 | *
121 | * @note This logging macro is called in the Fleet Provisioning library with
122 | * parameters wrapped in double parentheses to be ISO C89/C90 standard
123 | * compliant. For a reference POSIX implementation of the logging macros, refer
124 | * to the fleet_provisioning_config.h file, and the logging-stack in demos
125 | * folder of the [AWS IoT Embedded C SDK
126 | * repository](https://github.com/aws/aws-iot-device-sdk-embedded-C).
127 | *
128 | * Default value: Debug logs are turned off, and no code is generated for
129 | * calls to the macro in the Fleet Provisioning library on compilation.
130 | */
131 | #ifndef LogDebug
132 | #define LogDebug( message )
133 | #endif
134 |
135 | #endif /* FLEET_PROVISIONING_CONFIG_DEFAULTS_H_ */
136 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required ( VERSION 3.22.0 )
2 | project ( "Fleet Provisioning unit test"
3 | VERSION 1.2.1
4 | LANGUAGES C )
5 |
6 | # Allow the project to be organized into folders.
7 | set_property( GLOBAL PROPERTY USE_FOLDERS ON )
8 |
9 | # Use C90.
10 | set( CMAKE_C_STANDARD 90 )
11 | set( CMAKE_C_STANDARD_REQUIRED ON )
12 |
13 | # If no configuration is defined, turn everything on.
14 | if( NOT DEFINED COV_ANALYSIS AND NOT DEFINED UNITTEST )
15 | set( COV_ANALYSIS TRUE )
16 | set( UNITTEST TRUE )
17 | endif()
18 |
19 | # Do not allow in-source build.
20 | if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} )
21 | message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." )
22 | endif()
23 |
24 | # Set global path variable.
25 | get_filename_component( __MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE )
26 | set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "Fleet Provisioning repository root." )
27 | set( UNIT_TEST_DIR ${MODULE_ROOT_DIR}/test/unit-test CACHE INTERNAL "Fleet Provisioning unit test directory." )
28 | set( UNITY_DIR ${UNIT_TEST_DIR}/Unity CACHE INTERNAL "Unity library source directory." )
29 |
30 | # Configure options to always show in CMake GUI.
31 | option( BUILD_CLONE_SUBMODULES
32 | "Set this to ON to automatically clone any required Git submodules. When OFF, submodules must be manually cloned."
33 | ON )
34 |
35 | # Set output directories.
36 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
37 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
38 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
39 |
40 | # ====================== Coverity Analysis Configuration ======================
41 |
42 | if( COV_ANALYSIS )
43 | # Include filepaths for source and include.
44 | include( ${MODULE_ROOT_DIR}/fleetprovisioningFilePaths.cmake )
45 |
46 | # Target for Coverity analysis that builds the library.
47 | add_library( coverity_analysis
48 | ${FLEET_PROVISIONING_SOURCES} )
49 |
50 | # Fleet Provisioning public include path and test config file.
51 | target_include_directories( coverity_analysis PUBLIC
52 | ${FLEET_PROVISIONING_INCLUDE_PUBLIC_DIRS}
53 | "${CMAKE_CURRENT_LIST_DIR}/include" )
54 |
55 |
56 | # Build without debug enabled when performing static analysis
57 | target_compile_options(coverity_analysis PUBLIC -DNDEBUG -DDISABLE_LOGGING)
58 | endif()
59 |
60 | # ============================ Test Configuration ============================
61 |
62 | if( UNITTEST )
63 | # Include Unity build configuration.
64 | include( unit-test/unity_build.cmake )
65 |
66 | # Check if the Unity source directory exists. If it does not exist and the
67 | # BUILD_CLONE_SUBMODULES configuration is enabled, clone the Unity submodule.
68 | if( NOT EXISTS ${UNITY_DIR}/src )
69 | # Attempt to clone Unity.
70 | if( ${BUILD_CLONE_SUBMODULES} )
71 | clone_unity()
72 | else()
73 | message( FATAL_ERROR "The required submodule Unity does not exist. Either clone it manually, or set BUILD_CLONE_SUBMODULES to 1 to automatically clone it during build." )
74 | endif()
75 | endif()
76 |
77 | # Use CTest utility for managing test runs.
78 | enable_testing()
79 |
80 | # Add build target for Unity, required for unit testing.
81 | add_unity_target()
82 |
83 | # Add functions to enable Unity based tests and coverage.
84 | include( ${MODULE_ROOT_DIR}/tools/unity/create_test.cmake )
85 |
86 | # Include build configuration for unit tests.
87 | add_subdirectory( unit-test )
88 |
89 | # ====================== Coverage Analysis configuration ======================
90 |
91 | # Add a target for running coverage on tests.
92 | add_custom_target( coverage
93 | COMMAND ${CMAKE_COMMAND} -DUNITY_DIR=${UNITY_DIR}
94 | -P ${MODULE_ROOT_DIR}/tools/unity/coverage.cmake
95 | DEPENDS unity fleet_provisioning_utest
96 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} )
97 | endif()
98 |
--------------------------------------------------------------------------------
/test/cbmc/.gitignore:
--------------------------------------------------------------------------------
1 | # Emitted when running CBMC proofs
2 | proofs/**/logs
3 | proofs/**/gotos
4 | proofs/**/report
5 | proofs/**/html
6 | proofs/output
7 |
8 | # Emitted by CBMC Viewer
9 | TAGS-*
10 |
11 | # Emitted by Arpa
12 | arpa_cmake/
13 | arpa-validation-logs/
14 | Makefile.arpa
15 |
16 | # Emitted by litani
17 | .ninja_deps
18 | .ninja_log
19 | .litani_cache_dir
20 |
21 | # These files should be overwritten whenever prepare.py runs
22 | cbmc-batch.yaml
23 |
24 | __pycache__/
25 |
--------------------------------------------------------------------------------
/test/cbmc/include/README.md:
--------------------------------------------------------------------------------
1 | CBMC proof include files
2 | ========================
3 |
4 | This directory contains include files written for CBMC proof. It is
5 | common to write some code to model aspects of the system under test,
6 | and the header files for this code go here.
7 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_GetRegisterThingTopic/FleetProvisioning_GetRegisterThingTopic_harness.c:
--------------------------------------------------------------------------------
1 | /*
2 | * AWS IoT Fleet Provisioning v1.2.1
3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | *
5 | * SPDX-License-Identifier: MIT
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | * this software and associated documentation files (the "Software"), to deal in
9 | * the Software without restriction, including without limitation the rights to
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | * the Software, and to permit persons to whom the Software is furnished to do so,
12 | * subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /**
26 | * @file FleetProvisioning_GetRegisterThingTopic_harness.c
27 | * @brief Implements the proof harness for FleetProvisioning_GetRegisterThingTopic function.
28 | */
29 |
30 | #include
31 | #include "fleet_provisioning.h"
32 |
33 | void harness()
34 | {
35 | char * pTopicBuffer;
36 | uint16_t topicBufferLength;
37 | FleetProvisioningFormat_t format;
38 | FleetProvisioningApiTopics_t topic;
39 | const char * pTemplateName;
40 | uint16_t templateNameLength;
41 | uint16_t * pOutLength;
42 |
43 | __CPROVER_assume( topicBufferLength < CBMC_MAX_OBJECT_SIZE );
44 |
45 | /* +1 is to ensure that we run the function for invalid template name
46 | * lengths as well. */
47 | __CPROVER_assume( templateNameLength <= ( FP_TEMPLATENAME_MAX_LENGTH + 1 ) );
48 |
49 | pTopicBuffer = malloc( topicBufferLength );
50 | pTemplateName = malloc( templateNameLength );
51 | pOutLength = malloc( sizeof( *pOutLength ) );
52 |
53 | FleetProvisioning_GetRegisterThingTopic( pTopicBuffer,
54 | topicBufferLength,
55 | format,
56 | topic,
57 | pTemplateName,
58 | templateNameLength,
59 | pOutLength );
60 | }
61 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_GetRegisterThingTopic/Makefile:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | HARNESS_ENTRY = harness
5 | HARNESS_FILE = FleetProvisioning_GetRegisterThingTopic_harness
6 |
7 | # This should be a unique identifier for this proof, and will appear on the
8 | # Litani dashboard. It can be human-readable and contain spaces if you wish.
9 | PROOF_UID = FleetProvisioning_GetRegisterThingTopic
10 |
11 | DEFINES +=
12 | INCLUDES +=
13 |
14 | REMOVE_FUNCTION_BODY +=
15 | UNWINDSET +=
16 |
17 | PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
18 | PROJECT_SOURCES += $(SRCDIR)/source/fleet_provisioning.c
19 |
20 | include ../Makefile.common
21 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_GetRegisterThingTopic/README.md:
--------------------------------------------------------------------------------
1 | FleetProvisioning_GetRegisterThingTopic proof
2 | ==============
3 |
4 | This directory contains a memory safety proof for FleetProvisioning_GetRegisterThingTopic.
5 |
6 | To run the proof.
7 | -------------
8 |
9 | * Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer`
10 | to your path.
11 | * Run `make`.
12 | * Open html/index.html in a web browser.
13 |
14 | To use [`arpa`](https://awslabs.github.io/aws-proof-build-assistant) to simplify writing Makefiles.
15 | -------------
16 |
17 | * Run `make arpa` to generate a Makefile.arpa that contains relevant build information for the proof.
18 | * Use Makefile.arpa as the starting point for your proof Makefile by:
19 | 1. Modifying Makefile.arpa (if required).
20 | 2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`).
21 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_GetRegisterThingTopic/cbmc-proof.txt:
--------------------------------------------------------------------------------
1 | # This file marks this directory as containing a CBMC proof.
2 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_GetRegisterThingTopic/cbmc-viewer.json:
--------------------------------------------------------------------------------
1 | { "expected-missing-functions":
2 | [
3 |
4 | ],
5 | "proof-name": "FleetProvisioning_GetRegisterThingTopic",
6 | "proof-root": "test/cbmc/proofs"
7 | }
8 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_MatchTopic/FleetProvisioning_MatchTopic_harness.c:
--------------------------------------------------------------------------------
1 | /*
2 | * AWS IoT Fleet Provisioning v1.2.1
3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | *
5 | * SPDX-License-Identifier: MIT
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | * this software and associated documentation files (the "Software"), to deal in
9 | * the Software without restriction, including without limitation the rights to
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | * the Software, and to permit persons to whom the Software is furnished to do so,
12 | * subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /**
26 | * @file FleetProvisioning_MatchTopic_harness.c
27 | * @brief Implements the proof harness for FleetProvisioning_MatchTopic function.
28 | */
29 |
30 | #include
31 | #include "fleet_provisioning.h"
32 |
33 | void harness()
34 | {
35 | const char * pTopic;
36 | uint16_t topicLength;
37 | FleetProvisioningTopic_t * pOutApi;
38 |
39 | __CPROVER_assume( topicLength < TOPIC_STRING_LENGTH_MAX );
40 |
41 | pTopic = malloc( topicLength );
42 | pOutApi = malloc( sizeof( *pOutApi ) );
43 |
44 | FleetProvisioning_MatchTopic( pTopic,
45 | topicLength,
46 | pOutApi );
47 | }
48 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_MatchTopic/Makefile:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | HARNESS_ENTRY = harness
5 | HARNESS_FILE = FleetProvisioning_MatchTopic_harness
6 |
7 | # This should be a unique identifier for this proof, and will appear on the
8 | # Litani dashboard. It can be human-readable and contain spaces if you wish.
9 | PROOF_UID = FleetProvisioning_MatchTopic
10 |
11 | # The topic length is bounded to reduce the proof run time. Memory safety on the
12 | # buffer holding the topic string can be proven within a reasonable bound. It
13 | # adds no value to the proof to input the largest possible topic string accepted
14 | # by AWS (64KB).
15 | TOPIC_STRING_LENGTH_MAX=200
16 |
17 | DEFINES += -DTOPIC_STRING_LENGTH_MAX=$(TOPIC_STRING_LENGTH_MAX)
18 | INCLUDES +=
19 |
20 | REMOVE_FUNCTION_BODY +=
21 |
22 | # The longest strncmp is against FLEET_PROVISIONING_CREATE_CERTIFICATE_FROM_CSR_API_PREFIX
23 | # length of which is 35. We unwind one more time than the bridge length.
24 | FLEET_PROVISIONING_API_BRIDGE_LENGTH=36
25 | UNWINDSET += strncmp.0:$(FLEET_PROVISIONING_API_BRIDGE_LENGTH)
26 |
27 | # Enough to unwind the consumeTemplateName loop TOPIC_STRING_LENGTH_MAX times
28 | # as template name in the topic string can not be longer than the topic string
29 | # length.
30 | UNWINDSET += __CPROVER_file_local_fleet_provisioning_c_consumeTemplateName.0:$(TOPIC_STRING_LENGTH_MAX)
31 |
32 | PROOF_SOURCES += $(PROOFDIR)/$(HARNESS_FILE).c
33 | PROJECT_SOURCES += $(SRCDIR)/source/fleet_provisioning.c
34 |
35 | include ../Makefile.common
36 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_MatchTopic/README.md:
--------------------------------------------------------------------------------
1 | FleetProvisioning_MatchTopic proof
2 | ==============
3 |
4 | This directory contains a memory safety proof for FleetProvisioning_MatchTopic.
5 |
6 | To run the proof.
7 | -------------
8 |
9 | * Add `cbmc`, `goto-cc`, `goto-instrument`, `goto-analyzer`, and `cbmc-viewer`
10 | to your path.
11 | * Run `make`.
12 | * Open html/index.html in a web browser.
13 |
14 | To use [`arpa`](https://awslabs.github.io/aws-proof-build-assistant) to simplify writing Makefiles.
15 | -------------
16 |
17 | * Run `make arpa` to generate a Makefile.arpa that contains relevant build information for the proof.
18 | * Use Makefile.arpa as the starting point for your proof Makefile by:
19 | 1. Modifying Makefile.arpa (if required).
20 | 2. Including Makefile.arpa into the existing proof Makefile (add `sinclude Makefile.arpa` at the bottom of the Makefile, right before `include ../Makefile.common`).
21 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_MatchTopic/cbmc-proof.txt:
--------------------------------------------------------------------------------
1 | # This file marks this directory as containing a CBMC proof.
2 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/FleetProvisioning_MatchTopic/cbmc-viewer.json:
--------------------------------------------------------------------------------
1 | { "expected-missing-functions":
2 | [
3 |
4 | ],
5 | "proof-name": "FleetProvisioning_MatchTopic",
6 | "proof-root": "test/cbmc/proofs"
7 | }
8 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/Makefile-project-defines:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | # The first line sets the emacs major mode to Makefile
3 |
4 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | ################################################################
8 | # Use this file to give project-specific definitions of the command
9 | # line arguments to pass to CBMC tools like goto-cc to build the goto
10 | # binaries and cbmc to do the property and coverage checking.
11 | #
12 | # Use this file to override most default definitions of variables in
13 | # Makefile.common.
14 | ################################################################
15 |
16 | # Flags to pass to goto-cc for compilation (typically those passed to gcc -c)
17 | COMPILE_FLAGS += -fPIC -std=gnu90
18 |
19 | # Flags to pass to goto-cc for linking (typically those passed to gcc)
20 | # LINK_FLAGS =
21 |
22 | # Preprocessor include paths -I...
23 | # Consider adding
24 | # INCLUDES += -I$(CBMC_ROOT)/include
25 | # You will want to decide what order that comes in relative to the other
26 | # include directories in your project.
27 | #
28 | INCLUDES += -I$(CBMC_ROOT)/include
29 | INCLUDES += -I$(SRCDIR)/source/include
30 | INCLUDES += -I$(SRCDIR)/test/include
31 |
32 | # Preprocessor definitions -D...
33 | # DEFINES =
34 |
35 | # Path to arpa executable
36 | # ARPA =
37 |
38 | # Flags to pass to cmake for building the project
39 | # ARPA_CMAKE_FLAGS =
40 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/Makefile-project-targets:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | # The first line sets the emacs major mode to Makefile
3 |
4 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | ################################################################
8 | # Use this file to give project-specific targets, including targets
9 | # that may depend on targets defined in Makefile.common.
10 | ################################################################
11 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/Makefile-project-testing:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | # The first line sets the emacs major mode to Makefile
3 |
4 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 | # SPDX-License-Identifier: Apache-2.0
6 |
7 | ################################################################
8 | # Use this file to define project-specific targets and definitions for
9 | # unit testing or continuous integration that may depend on targets
10 | # defined in Makefile.common
11 | ################################################################
12 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/Makefile-template-defines:
--------------------------------------------------------------------------------
1 |
2 | # Absolute path to the root of the source tree.
3 | #
4 | SRCDIR ?= $(abspath $(PROOF_ROOT)/../../..)
5 |
6 |
7 | # Absolute path to the litani script.
8 | #
9 | LITANI ?= litani
10 |
11 |
12 | # Name of this proof project, displayed in proof reports. For example,
13 | # "s2n" or "Amazon FreeRTOS". For projects with multiple proof roots,
14 | # this may be overridden on the command-line to Make, for example
15 | #
16 | # make PROJECT_NAME="FreeRTOS MQTT" report
17 | #
18 | PROJECT_NAME = "Fleet-Provisioning-for-AWS-IoT-embedded-sdk"
19 |
20 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/Makefile.common:
--------------------------------------------------------------------------------
1 | # -*- mode: makefile -*-
2 | # The first line sets the emacs major mode to Makefile
3 |
4 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 | # SPDX-License-Identifier: MIT-0
6 |
7 | CBMC_STARTER_KIT_VERSION = CBMC starter kit 2.11
8 |
9 | ################################################################
10 | # The CBMC Starter Kit depends on the files Makefile.common and
11 | # run-cbmc-proofs.py. They are installed by the setup script
12 | # cbmc-starter-kit-setup and updated to the latest version by the
13 | # update script cbmc-starter-kit-update. For more information about
14 | # the starter kit and these files and these scripts, see
15 | # https://model-checking.github.io/cbmc-starter-kit
16 | #
17 | # Makefile.common implements what we consider to be some best
18 | # practices for using cbmc for software verification.
19 | #
20 | # Section I gives default values for a large number of Makefile
21 | # variables that control
22 | # * how your code is built (include paths, etc),
23 | # * what program transformations are applied to your code (loop
24 | # unwinding, etc), and
25 | # * what properties cbmc checks for in your code (memory safety, etc).
26 | #
27 | # These variables are defined below with definitions of the form
28 | # VARIABLE ?= DEFAULT_VALUE
29 | # meaning VARIABLE is set to DEFAULT_VALUE if VARIABLE has not already
30 | # been given a value.
31 | #
32 | # For your project, you can override these default values with
33 | # project-specific definitions in Makefile-project-defines.
34 | #
35 | # For any individual proof, you can override these default values and
36 | # project-specific values with proof-specific definitions in the
37 | # Makefile for your proof.
38 | #
39 | # The definitions in the proof Makefile override definitions in the
40 | # project Makefile-project-defines which override definitions in this
41 | # Makefile.common.
42 | #
43 | # Section II uses the values defined in Section I to build your code, run
44 | # your proof, and build a report of your results. You should not need
45 | # to modify or override anything in Section II, but you may want to
46 | # read it to understand how the values defined in Section I control
47 | # things.
48 | #
49 | # To use Makefile.common, set variables as described above as needed,
50 | # and then for each proof,
51 | #
52 | # * Create a subdirectory .
53 | # * Write a proof harness (a function) with the name
54 | # in a file with the name /.c
55 | # * Write a makefile with the name /Makefile that looks
56 | # something like
57 | #
58 | # HARNESS_FILE=
59 | # HARNESS_ENTRY=
60 | # PROOF_UID=
61 | #
62 | # PROJECT_SOURCES += $(SRCDIR)/libraries/api_1.c
63 | # PROJECT_SOURCES += $(SRCDIR)/libraries/api_2.c
64 | #
65 | # PROOF_SOURCES += $(PROOFDIR)/harness.c
66 | # PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_a.c
67 | # PROOF_SOURCES += $(SRCDIR)/cbmc/proofs/stub_b.c
68 | #
69 | # UNWINDSET += foo.0:3
70 | # UNWINDSET += bar.1:6
71 | #
72 | # REMOVE_FUNCTION_BODY += api_stub_a
73 | # REMOVE_FUNCTION_BODY += api_stub_b
74 | #
75 | # DEFINES = -DDEBUG=0
76 | #
77 | # include ../Makefile.common
78 | #
79 | # * Change directory to and run make
80 | #
81 | # The proof setup script cbmc-starter-kit-setup-proof from the CBMC
82 | # Starter Kit will do most of this for, creating a directory and
83 | # writing a basic Makefile and proof harness into it that you can edit
84 | # as described above.
85 | #
86 | # Warning: If you get results that are hard to explain, consider
87 | # running "make clean" or "make veryclean" before "make" if you get
88 | # results that are hard to explain. Dependency handling in this
89 | # Makefile.common may not be perfect.
90 |
91 | SHELL=/bin/bash
92 |
93 | default: report
94 |
95 | ################################################################
96 | ################################################################
97 | ## Section I: This section gives common variable definitions.
98 | ##
99 | ## Override these definitions in Makefile-project-defines or
100 | ## your proof Makefile.
101 | ##
102 | ## Remember that Makefile.common and Makefile-project-defines are
103 | ## included into the proof Makefile in your proof directory, so all
104 | ## relative pathnames defined there should be relative to your proof
105 | ## directory.
106 |
107 | ################################################################
108 | # Define the layout of the source tree and the proof subtree
109 | #
110 | # Generally speaking,
111 | #
112 | # SRCDIR = the root of the repository
113 | # CBMC_ROOT = /srcdir/cbmc
114 | # PROOF_ROOT = /srcdir/cbmc/proofs
115 | # PROOF_SOURCE = /srcdir/cbmc/sources
116 | # PROOF_INCLUDE = /srcdir/cbmc/include
117 | # PROOF_STUB = /srcdir/cbmc/stubs
118 | # PROOFDIR = the directory containing the Makefile for your proof
119 | #
120 | # The path /srcdir/cbmc used in the example above is determined by the
121 | # setup script cbmc-starter-kit-setup. Projects usually create a cbmc
122 | # directory somewhere in the source tree, and run the setup script in
123 | # that directory. The value of CBMC_ROOT becomes the absolute path to
124 | # that directory.
125 | #
126 | # The location of that cbmc directory in the source tree affects the
127 | # definition of SRCDIR, which is defined in terms of the relative path
128 | # from a proof directory to the repository root. The definition is
129 | # usually determined by the setup script cbmc-starter-kit-setup and
130 | # written to Makefile-template-defines, but you can override it for a
131 | # project in Makefile-project-defines and for a specific proof in the
132 | # Makefile for the proof.
133 |
134 | # Absolute path to the directory containing this Makefile.common
135 | # See https://ftp.gnu.org/old-gnu/Manuals/make-3.80/html_node/make_17.html
136 | #
137 | # Note: We compute the absolute paths to the makefiles in MAKEFILE_LIST
138 | # before we filter the list of makefiles for %/Makefile.common.
139 | # Otherwise an invocation of the form "make -f Makefile.common" will set
140 | # MAKEFILE_LIST to "Makefile.common" which will fail to match the
141 | # pattern %/Makefile.common.
142 | #
143 | MAKEFILE_PATHS = $(foreach makefile,$(MAKEFILE_LIST),$(abspath $(makefile)))
144 | PROOF_ROOT = $(dir $(filter %/Makefile.common,$(MAKEFILE_PATHS)))
145 |
146 | CBMC_ROOT = $(shell dirname $(PROOF_ROOT))
147 | PROOF_SOURCE = $(CBMC_ROOT)/sources
148 | PROOF_INCLUDE = $(CBMC_ROOT)/include
149 | PROOF_STUB = $(CBMC_ROOT)/stubs
150 |
151 | # Project-specific definitions to override default definitions below
152 | # * Makefile-project-defines will never be overwritten
153 | # * Makefile-template-defines may be overwritten when the starter
154 | # kit is updated
155 | sinclude $(PROOF_ROOT)/Makefile-project-defines
156 | sinclude $(PROOF_ROOT)/Makefile-template-defines
157 |
158 | # SRCDIR is the path to the root of the source tree
159 | # This is a default definition that is frequently overridden in
160 | # another Makefile, see the discussion of SRCDIR above.
161 | SRCDIR ?= $(abspath ../..)
162 |
163 | # PROOFDIR is the path to the directory containing the proof harness
164 | PROOFDIR ?= $(abspath .)
165 |
166 | ################################################################
167 | # Define how to run CBMC
168 |
169 | # Do property checking with the external SAT solver given by
170 | # EXTERNAL_SAT_SOLVER. Do coverage checking with the default solver,
171 | # since coverage checking requires the use of an incremental solver.
172 | # The EXTERNAL_SAT_SOLVER variable is typically set (if it is at all)
173 | # as an environment variable or as a makefile variable in
174 | # Makefile-project-defines.
175 | #
176 | # For a particular proof, if the default solver is faster, do property
177 | # checking with the default solver by including this definition in the
178 | # proof Makefile:
179 | # USE_EXTERNAL_SAT_SOLVER =
180 | #
181 | ifneq ($(strip $(EXTERNAL_SAT_SOLVER)),)
182 | USE_EXTERNAL_SAT_SOLVER ?= --external-sat-solver $(EXTERNAL_SAT_SOLVER)
183 | endif
184 | CHECKFLAGS += $(USE_EXTERNAL_SAT_SOLVER)
185 |
186 | # Job pools
187 | # For version of Litani that are new enough (where `litani print-capabilities`
188 | # prints "pools"), proofs for which `EXPENSIVE = true` is set can be added to a
189 | # "job pool" that restricts how many expensive proofs are run at a time. All
190 | # other proofs will be built in parallel as usual.
191 | #
192 | # In more detail: all compilation, instrumentation, and report jobs are run with
193 | # full parallelism as usual, even for expensive proofs. The CBMC jobs for
194 | # non-expensive proofs are also run in parallel. The only difference is that the
195 | # CBMC safety checks and coverage checks for expensive proofs are run with a
196 | # restricted parallelism level. At any one time, only N of these jobs are run at
197 | # once, amongst all the proofs.
198 | #
199 | # To configure N, Litani needs to be initialized with a pool called "expensive".
200 | # For example, to only run two CBMC safety/coverage jobs at a time from amongst
201 | # all the proofs, you would initialize litani like
202 | # litani init --pools expensive:2
203 | # The run-cbmc-proofs.py script takes care of this initialization through the
204 | # --expensive-jobs-parallelism flag.
205 | #
206 | # To enable this feature, set
207 | # the ENABLE_POOLS variable when running Make, like
208 | # `make ENABLE_POOLS=true report`
209 | # The run-cbmc-proofs.py script takes care of this through the
210 | # --restrict-expensive-jobs flag.
211 |
212 | ifeq ($(strip $(ENABLE_POOLS)),)
213 | POOL =
214 | INIT_POOLS =
215 | else ifeq ($(strip $(EXPENSIVE)),)
216 | POOL =
217 | INIT_POOLS =
218 | else
219 | POOL = --pool expensive
220 | INIT_POOLS = --pools expensive:1
221 | endif
222 |
223 | # Similar to the pool feature above. If Litani is new enough, enable
224 | # profiling CBMC's memory use.
225 | ifeq ($(strip $(ENABLE_MEMORY_PROFILING)),)
226 | MEMORY_PROFILING =
227 | else
228 | MEMORY_PROFILING = --profile-memory
229 | endif
230 |
231 | # Property checking flags
232 | #
233 | # Each variable below controls a specific property checking flag
234 | # within CBMC. If desired, a property flag can be disabled within
235 | # a particular proof by nulling the corresponding variable when CBMC's default
236 | # is not to perform such checks, or setting to --no--check when CBMC's
237 | # default is to perform such checks. For instance, the following lines:
238 | #
239 | # CBMC_FLAG_POINTER_CHECK = --no-pointer-check
240 | # CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK =
241 | #
242 | # would disable pointer checks and unsigned overflow checks with CBMC flag
243 | # within:
244 | # * an entire project when added to Makefile-project-defines
245 | # * a specific proof when added to the harness Makefile
246 |
247 | CBMC_FLAG_MALLOC_MAY_FAIL ?= # set to --no-malloc-may-fail to disable
248 | CBMC_FLAG_BOUNDS_CHECK ?= # set to --no-bounds-check to disable
249 | CBMC_FLAG_CONVERSION_CHECK ?= --conversion-check
250 | CBMC_FLAG_DIV_BY_ZERO_CHECK ?= # set to --no-div-by-zero-check to disable
251 | CBMC_FLAG_FLOAT_OVERFLOW_CHECK ?= --float-overflow-check
252 | CBMC_FLAG_NAN_CHECK ?= --nan-check
253 | CBMC_FLAG_POINTER_CHECK ?= #set to --no-pointer-check to disable
254 | CBMC_FLAG_POINTER_OVERFLOW_CHECK ?= --pointer-overflow-check
255 | CBMC_FLAG_POINTER_PRIMITIVE_CHECK ?= # set to --no-pointer-primitive-check to disable
256 | CBMC_FLAG_SIGNED_OVERFLOW_CHECK ?= # set to --no-signed-overflow-check to disable
257 | CBMC_FLAG_UNDEFINED_SHIFT_CHECK ?= # set to --no-undefined-shift-check to disable
258 | CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK ?= --unsigned-overflow-check
259 | CBMC_FLAG_UNWINDING_ASSERTIONS ?= # set to --no-unwinding-assertions to disable
260 | CBMC_DEFAULT_UNWIND ?= --unwind 1
261 | CBMC_FLAG_FLUSH ?= --flush
262 |
263 | # CBMC flags used for property checking and coverage checking
264 |
265 | CBMCFLAGS += $(CBMC_FLAG_FLUSH)
266 |
267 | # CBMC 6.0.0 enables all standard checks by default, which can make coverage analysis
268 | # very slow. See https://github.com/diffblue/cbmc/issues/8389
269 | # For now, we disable these checks when generating coverage info.
270 | COVERFLAGS ?= --no-standard-checks --malloc-may-fail --malloc-fail-null
271 |
272 | # CBMC flags used for property checking
273 |
274 | CHECKFLAGS += $(CBMC_FLAG_BOUNDS_CHECK)
275 | CHECKFLAGS += $(CBMC_FLAG_CONVERSION_CHECK)
276 | CHECKFLAGS += $(CBMC_FLAG_DIV_BY_ZERO_CHECK)
277 | CHECKFLAGS += $(CBMC_FLAG_FLOAT_OVERFLOW_CHECK)
278 | CHECKFLAGS += $(CBMC_FLAG_NAN_CHECK)
279 | CHECKFLAGS += $(CBMC_FLAG_POINTER_CHECK)
280 | CHECKFLAGS += $(CBMC_FLAG_POINTER_OVERFLOW_CHECK)
281 | CHECKFLAGS += $(CBMC_FLAG_POINTER_PRIMITIVE_CHECK)
282 | CHECKFLAGS += $(CBMC_FLAG_SIGNED_OVERFLOW_CHECK)
283 | CHECKFLAGS += $(CBMC_FLAG_UNDEFINED_SHIFT_CHECK)
284 | CHECKFLAGS += $(CBMC_FLAG_UNSIGNED_OVERFLOW_CHECK)
285 |
286 | # Additional CBMC flag to CBMC control verbosity.
287 | #
288 | # Meaningful values are
289 | # 0 none
290 | # 1 only errors
291 | # 2 + warnings
292 | # 4 + results
293 | # 6 + status/phase information
294 | # 8 + statistical information
295 | # 9 + progress information
296 | # 10 + debug info
297 | #
298 | # Uncomment the following line or set in Makefile-project-defines
299 | # CBMC_VERBOSITY ?= --verbosity 4
300 |
301 | # Additional CBMC flag to control how CBMC treats static variables.
302 | #
303 | # NONDET_STATIC is a list of flags of the form --nondet-static
304 | # and --nondet-static-exclude VAR. The --nondet-static flag causes
305 | # CBMC to initialize static variables with unconstrained value
306 | # (ignoring initializers and default zero-initialization). The
307 | # --nondet-static-exclude VAR excludes VAR for the variables
308 | # initialized with unconstrained values.
309 | NONDET_STATIC ?=
310 |
311 | # Flags to pass to goto-cc for compilation and linking
312 | COMPILE_FLAGS ?= -Wall -Werror
313 | LINK_FLAGS ?= -Wall -Werror
314 | EXPORT_FILE_LOCAL_SYMBOLS ?= --export-file-local-symbols
315 |
316 | # During instrumentation, it adds models of C library functions
317 | ADD_LIBRARY_FLAG := --add-library
318 |
319 | # Preprocessor include paths -I...
320 | INCLUDES ?=
321 |
322 | # Preprocessor definitions -D...
323 | DEFINES ?=
324 |
325 | # CBMC object model
326 | #
327 | # CBMC_OBJECT_BITS is the number of bits in a pointer CBMC uses for
328 | # the id of the object to which a pointer is pointing. CBMC uses 8
329 | # bits for the object id by default. The remaining bits in the pointer
330 | # are used for offset into the object. This limits the size of the
331 | # objects that CBMC can model. This Makefile defines this bound on
332 | # object size to be CBMC_MAX_OBJECT_SIZE. You are likely to get
333 | # unexpected results if you try to malloc an object larger than this
334 | # bound.
335 | CBMC_OBJECT_BITS ?= 8
336 |
337 | # CBMC loop unwinding (Normally set in the proof Makefile)
338 | #
339 | # UNWINDSET is a list of pairs of the form foo.1:4 meaning that
340 | # CBMC should unwind loop 1 in function foo no more than 4 times.
341 | # For historical reasons, the number 4 is one more than the number
342 | # of times CBMC actually unwinds the loop.
343 | UNWINDSET ?=
344 |
345 | # CBMC early loop unwinding (Normally set in the proof Makefile)
346 | #
347 | # Most users can ignore this variable.
348 | #
349 | # This variable exists to support the use of loop and function
350 | # contracts, two features under development for CBMC. Checking the
351 | # assigns clause for function contracts and loop invariants currently
352 | # assumes loop-free bodies for loops and functions with contracts
353 | # (possibly after replacing nested loops with their own loop
354 | # contracts). To satisfy this requirement, it may be necessary to
355 | # unwind some loops before the function contract and loop invariant
356 | # transformations are applied to the goto program. This variable
357 | # CPROVER_LIBRARY_UNWINDSET is identical to UNWINDSET, and we assume that the
358 | # loops mentioned in CPROVER_LIBRARY_UNWINDSET and UNWINDSET are disjoint.
359 | CPROVER_LIBRARY_UNWINDSET ?=
360 |
361 | # CBMC function removal (Normally set set in the proof Makefile)
362 | #
363 | # REMOVE_FUNCTION_BODY is a list of function names. CBMC will "undefine"
364 | # the function, and CBMC will treat the function as having no side effects
365 | # and returning an unconstrained value of the appropriate return type.
366 | # The list should include the names of functions being stubbed out.
367 | REMOVE_FUNCTION_BODY ?=
368 |
369 | # CBMC function pointer restriction (Normally set in the proof Makefile)
370 | #
371 | # RESTRICT_FUNCTION_POINTER is a list of function pointer restriction
372 | # instructions of the form:
373 | #
374 | # .function_pointer_call./[,]*
375 | #
376 | # The function pointer call number in the specified function gets
377 | # rewritten to a case switch over a finite list of functions.
378 | # If some possible target functions are omitted from the list a counter
379 | # example trace will be found by CBMC, i.e. the transformation is sound.
380 | # If the target functions are file-local symbols, then mangled names must
381 | # be used.
382 | RESTRICT_FUNCTION_POINTER ?=
383 |
384 | # The project source files (Normally set set in the proof Makefile)
385 | #
386 | # PROJECT_SOURCES is the list of project source files to compile,
387 | # including the source file defining the function under test.
388 | PROJECT_SOURCES ?=
389 |
390 | # The proof source files (Normally set in the proof Makefile)
391 | #
392 | # PROOF_SOURCES is the list of proof source files to compile, including
393 | # the proof harness, and including any function stubs being used.
394 | PROOF_SOURCES ?=
395 |
396 | # The number of seconds that CBMC should be allowed to run for before
397 | # being forcefully terminated. Currently, this is set to be less than
398 | # the time limit for a CodeBuild job, which is eight hours. If a proof
399 | # run takes longer than the time limit of the CI environment, the
400 | # environment will halt the proof run without updating the Litani
401 | # report, making the proof run appear to "hang".
402 | CBMC_TIMEOUT ?= 21600
403 |
404 | # CBMC string abstraction
405 | #
406 | # Replace all uses of char * by a struct that carries that string,
407 | # and also the underlying allocation and the C string length.
408 | STRING_ABSTRACTION ?=
409 | ifdef STRING_ABSTRACTION
410 | ifneq ($(strip $(STRING_ABSTRACTION)),)
411 | CBMC_STRING_ABSTRACTION := --string-abstraction
412 | endif
413 | endif
414 |
415 | # Optional configuration library flags
416 | OPT_CONFIG_LIBRARY ?=
417 | CBMC_OPT_CONFIG_LIBRARY := $(CBMC_FLAG_MALLOC_MAY_FAIL) $(CBMC_STRING_ABSTRACTION)
418 |
419 | # Proof writers could add function contracts in their source code.
420 | # These contracts are ignored by default, but may be enabled in two distinct
421 | # contexts using the following two variables:
422 | # 1. To check whether one or more function contracts are sound with respect to
423 | # the function implementation, CHECK_FUNCTION_CONTRACTS should be a list of
424 | # function names. Use CHECK_FUNCTION_CONTRACTS_REC to check contracts on
425 | # recursive functions.
426 | # 2. To replace calls to certain functions with their correspondent function
427 | # contracts, USE_FUNCTION_CONTRACTS should be a list of function names.
428 | # One must check separately whether a function contract is sound before
429 | # replacing it in calling contexts.
430 | CHECK_FUNCTION_CONTRACTS ?=
431 | CBMC_CHECK_FUNCTION_CONTRACTS := $(patsubst %,--enforce-contract %, $(CHECK_FUNCTION_CONTRACTS))
432 |
433 | CHECK_FUNCTION_CONTRACTS_REC ?=
434 | CBMC_CHECK_FUNCTION_CONTRACTS_REC := $(patsubst %,--enforce-contract-rec %, $(CHECK_FUNCTION_CONTRACTS_REC))
435 |
436 | USE_FUNCTION_CONTRACTS ?=
437 | CBMC_USE_FUNCTION_CONTRACTS := $(patsubst %,--replace-call-with-contract %, $(USE_FUNCTION_CONTRACTS))
438 |
439 | CODE_CONTRACTS := $(CHECK_FUNCTION_CONTRACTS)$(USE_FUNCTION_CONTRACTS)$(APPLY_LOOP_CONTRACTS)
440 |
441 | # Proof writers may also apply function contracts using the Dynamic Frame
442 | # Condition Checking (DFCC) mode. For more information on DFCC,
443 | # please see https://diffblue.github.io/cbmc/contracts-dev-spec-dfcc.html.
444 | USE_DYNAMIC_FRAMES ?=
445 | ifdef USE_DYNAMIC_FRAMES
446 | ifneq ($(strip $(USE_DYNAMIC_FRAMES)),)
447 | CBMC_USE_DYNAMIC_FRAMES := $(CBMC_OPT_CONFIG_LIBRARY) --dfcc $(HARNESS_ENTRY) $(CBMC_CHECK_FUNCTION_CONTRACTS_REC)
448 | endif
449 | endif
450 |
451 | # Similarly, proof writers could also add loop contracts in their source code
452 | # to obtain unbounded correctness proofs. Unlike function contracts, loop
453 | # contracts are not reusable and thus are checked and used simultaneously.
454 | # These contracts are also ignored by default, but may be enabled by setting
455 | # the APPLY_LOOP_CONTRACTS variable.
456 | APPLY_LOOP_CONTRACTS ?=
457 | ifdef APPLY_LOOP_CONTRACTS
458 | ifneq ($(strip $(APPLY_LOOP_CONTRACTS)),)
459 | CBMC_APPLY_LOOP_CONTRACTS := --apply-loop-contracts
460 | endif
461 | endif
462 |
463 | # The default unwind should only be used in DFCC mode without loop contracts.
464 | # When loop contracts are applied, we only unwind specified loops.
465 | # If any loops remain after loop contracts have been applied, CBMC might try
466 | # to unwind the program indefinitely, because we do not pass default unwind
467 | # (i.e., --unwind 1) to CBMC when in DFCC mode.
468 | # We must not use a default unwind command in DFCC mode, because contract instrumentation
469 | # introduces loops encoding write set inclusion checks that must be dynamically unwound during
470 | # symex.
471 | ifneq ($(strip $(USE_DYNAMIC_FRAMES)),)
472 | ifneq ($(strip $(APPLY_LOOP_CONTRACTS)),)
473 | UNWIND_0500_FLAGS=$(CBMC_UNWINDSET) $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_FLAG_UNWINDING_ASSERTIONS)
474 | UNWIND_0500_DESC="$(PROOF_UID): unwinding specified subset of loops"
475 | else
476 | UNWIND_0500_FLAGS=$(CBMC_UNWINDSET) $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_DEFAULT_UNWIND) $(CBMC_FLAG_UNWINDING_ASSERTIONS)
477 | UNWIND_0500_DESC="$(PROOF_UID): unwinding all loops"
478 | endif
479 | endif
480 |
481 | # Silence makefile output (eg, long litani commands) unless VERBOSE is set.
482 | ifndef VERBOSE
483 | MAKEFLAGS := $(MAKEFLAGS) -s
484 | endif
485 |
486 | ################################################################
487 | ################################################################
488 | ## Section II: This section defines the process of running a proof
489 | ##
490 | ## There should be no reason to edit anything below this line.
491 |
492 | ################################################################
493 | # Paths
494 |
495 | CBMC ?= cbmc
496 | GOTO_ANALYZER ?= goto-analyzer
497 | GOTO_CC ?= goto-cc
498 | GOTO_INSTRUMENT ?= goto-instrument
499 | CRANGLER ?= crangler
500 | VIEWER ?= cbmc-viewer
501 | VIEWER2 ?= cbmc-viewer
502 | CMAKE ?= cmake
503 |
504 | GOTODIR ?= $(PROOFDIR)/gotos
505 | LOGDIR ?= $(PROOFDIR)/logs
506 |
507 | PROJECT ?= project
508 | PROOF ?= proof
509 |
510 | HARNESS_GOTO ?= $(GOTODIR)/$(HARNESS_FILE)
511 | PROJECT_GOTO ?= $(GOTODIR)/$(PROJECT)
512 | PROOF_GOTO ?= $(GOTODIR)/$(PROOF)
513 |
514 | ################################################################
515 | # Useful macros for values that are hard to reference
516 | SPACE :=$() $()
517 | COMMA :=,
518 |
519 | ################################################################
520 | # Set C compiler defines
521 |
522 | CBMCFLAGS += --object-bits $(CBMC_OBJECT_BITS)
523 |
524 | DEFINES += -DCBMC=1
525 | DEFINES += -DCBMC_OBJECT_BITS=$(CBMC_OBJECT_BITS)
526 | DEFINES += -DCBMC_MAX_OBJECT_SIZE="(SIZE_MAX>>(CBMC_OBJECT_BITS+1))"
527 |
528 | # CI currently assumes cbmc invocation has at most one --unwindset
529 |
530 | # UNWINDSET is designed for user code (i.e., proof and project code)
531 | ifdef UNWINDSET
532 | ifneq ($(strip $(UNWINDSET)),)
533 | CBMC_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(UNWINDSET)))
534 | endif
535 | endif
536 |
537 | # CPROVER_LIBRARY_UNWINDSET is designed for CPROVER library functions
538 | ifdef CPROVER_LIBRARY_UNWINDSET
539 | ifneq ($(strip $(CPROVER_LIBRARY_UNWINDSET)),)
540 | CBMC_CPROVER_LIBRARY_UNWINDSET := --unwindset $(subst $(SPACE),$(COMMA),$(strip $(CPROVER_LIBRARY_UNWINDSET)))
541 | endif
542 | endif
543 |
544 | CBMC_REMOVE_FUNCTION_BODY := $(patsubst %,--remove-function-body %, $(REMOVE_FUNCTION_BODY))
545 |
546 | ifdef RESTRICT_FUNCTION_POINTER
547 | ifneq ($(strip $(RESTRICT_FUNCTION_POINTER)),)
548 | CBMC_RESTRICT_FUNCTION_POINTER := $(patsubst %,--restrict-function-pointer %, $(RESTRICT_FUNCTION_POINTER))
549 | endif
550 | endif
551 |
552 | ################################################################
553 | # Targets for rewriting source files with crangler
554 |
555 | # Construct crangler configuration files
556 | #
557 | # REWRITTEN_SOURCES is a list of crangler output files source.i.
558 | # This target assumes that for each source.i
559 | # * source.i_SOURCE is the path to a source file,
560 | # * source.i_FUNCTIONS is a list of functions (may be empty)
561 | # * source.i_OBJECTS is a list of variables (may be empty)
562 | # This target constructs the crangler configuration file source.i.json
563 | # of the form
564 | # {
565 | # "sources": [ "/proj/code.c" ],
566 | # "includes": [ "/proj/include" ],
567 | # "defines": [ "VAR=1" ],
568 | # "functions": [ {"function_name": ["remove static"]} ],
569 | # "objects": [ {"variable_name": ["remove static"]} ],
570 | # "output": "source.i"
571 | # }
572 | # to remove the static attribute from function_name and variable_name
573 | # in the source file source.c and write the result to source.i.
574 | #
575 | # This target assumes that filenames include no spaces and that
576 | # the INCLUDES and DEFINES variables include no spaces after -I
577 | # and -D. For example, use "-DVAR=1" and not "-D VAR=1".
578 | #
579 | # Define *_SOURCE, *_FUNCTIONS, and *_OBJECTS in the proof Makefile.
580 | # The string source.i is usually an absolute path $(PROOFDIR)/code.i
581 | # to a file in the proof directory that contains the proof Makefile.
582 | # The proof Makefile usually includes the definitions
583 | # $(PROOFDIR)/code.i_SOURCE = /proj/code.c
584 | # $(PROOFDIR)/code.i_FUNCTIONS = function_name
585 | # $(PROOFDIR)/code.i_OBJECTS = variable_name
586 | # Because these definitions refer to PROOFDIR that is defined in this
587 | # Makefile.common, these definitions must appear after the inclusion
588 | # of Makefile.common in the proof Makefile.
589 | #
590 | $(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs).json: $($(rs)_SOURCE)))
591 | $(foreach rs,$(REWRITTEN_SOURCES),$(rs).json):
592 | echo '{'\
593 | '"sources": ['\
594 | '"$($(@:.json=)_SOURCE)"'\
595 | '],'\
596 | '"includes": ['\
597 | '$(subst $(SPACE),$(COMMA),$(patsubst -I%,"%",$(strip $(INCLUDES))))' \
598 | '],'\
599 | '"defines": ['\
600 | '$(subst $(SPACE),$(COMMA),$(patsubst -D%,"%",$(subst ",\",$(strip $(DEFINES)))))' \
601 | '],'\
602 | '"functions": ['\
603 | '{'\
604 | '$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_FUNCTIONS))))' \
605 | '}'\
606 | '],'\
607 | '"objects": ['\
608 | '{'\
609 | '$(subst ~, ,$(subst $(SPACE),$(COMMA),$(patsubst %,"%":["remove~static"],$($(@:.json=)_OBJECTS))))' \
610 | '}'\
611 | '],'\
612 | '"output": "$(@:.json=)"'\
613 | '}' > $@
614 |
615 | # Rewrite source files with crangler
616 | #
617 | $(foreach rs,$(REWRITTEN_SOURCES),$(eval $(rs): $(rs).json))
618 | $(REWRITTEN_SOURCES):
619 | $(LITANI) add-job \
620 | --command \
621 | '$(CRANGLER) $@.json' \
622 | --inputs $($@_SOURCE) \
623 | --outputs $@ \
624 | --stdout-file $(LOGDIR)/crangler-$(subst /,_,$(subst .,_,$@))-log.txt \
625 | --interleave-stdout-stderr \
626 | --pipeline-name "$(PROOF_UID)" \
627 | --ci-stage build \
628 | --description "$(PROOF_UID): removing static"
629 |
630 | ################################################################
631 | # Build targets that make the relevant .goto files
632 |
633 | # Compile project sources
634 | $(PROJECT_GOTO)0100.goto: $(PROJECT_SOURCES) $(REWRITTEN_SOURCES)
635 | $(LITANI) add-job \
636 | --command \
637 | '$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
638 | --inputs $^ \
639 | --outputs $@ \
640 | --stdout-file $(LOGDIR)/project_sources-log.txt \
641 | --pipeline-name "$(PROOF_UID)" \
642 | --ci-stage build \
643 | --description "$(PROOF_UID): building project binary"
644 |
645 | # Compile proof sources
646 | $(PROOF_GOTO)0100.goto: $(PROOF_SOURCES)
647 | $(LITANI) add-job \
648 | --command \
649 | '$(GOTO_CC) $(CBMC_VERBOSITY) $(COMPILE_FLAGS) $(EXPORT_FILE_LOCAL_SYMBOLS) $(INCLUDES) $(DEFINES) $^ -o $@' \
650 | --inputs $^ \
651 | --outputs $@ \
652 | --stdout-file $(LOGDIR)/proof_sources-log.txt \
653 | --pipeline-name "$(PROOF_UID)" \
654 | --ci-stage build \
655 | --description "$(PROOF_UID): building proof binary"
656 |
657 | # Remove function bodies from project sources
658 | $(PROJECT_GOTO)0200.goto: $(PROJECT_GOTO)0100.goto
659 | $(LITANI) add-job \
660 | --command \
661 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_REMOVE_FUNCTION_BODY) $^ $@' \
662 | --inputs $^ \
663 | --outputs $@ \
664 | --stdout-file $(LOGDIR)/remove_function_body-log.txt \
665 | --pipeline-name "$(PROOF_UID)" \
666 | --ci-stage build \
667 | --description "$(PROOF_UID): removing function bodies from project sources"
668 |
669 | # Link project and proof sources into the proof harness
670 | $(HARNESS_GOTO)0100.goto: $(PROOF_GOTO)0100.goto $(PROJECT_GOTO)0200.goto
671 | $(LITANI) add-job \
672 | --command '$(GOTO_CC) $(CBMC_VERBOSITY) --function $(HARNESS_ENTRY) $^ $(LINK_FLAGS) -o $@' \
673 | --inputs $^ \
674 | --outputs $@ \
675 | --stdout-file $(LOGDIR)/link_proof_project-log.txt \
676 | --pipeline-name "$(PROOF_UID)" \
677 | --ci-stage build \
678 | --description "$(PROOF_UID): linking project to proof"
679 |
680 | # Restrict function pointers
681 | $(HARNESS_GOTO)0200.goto: $(HARNESS_GOTO)0100.goto
682 | $(LITANI) add-job \
683 | --command \
684 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_RESTRICT_FUNCTION_POINTER) --remove-function-pointers $^ $@' \
685 | --inputs $^ \
686 | --outputs $@ \
687 | --stdout-file $(LOGDIR)/restrict_function_pointer-log.txt \
688 | --pipeline-name "$(PROOF_UID)" \
689 | --ci-stage build \
690 | --description "$(PROOF_UID): restricting function pointers in project sources"
691 |
692 | # Fill static variable with unconstrained values
693 | $(HARNESS_GOTO)0300.goto: $(HARNESS_GOTO)0200.goto
694 | ifneq ($(strip $(CODE_CONTRACTS)),)
695 | $(LITANI) add-job \
696 | --command 'cp $^ $@' \
697 | --inputs $^ \
698 | --outputs $@ \
699 | --stdout-file $(LOGDIR)/nondet_static-log.txt \
700 | --pipeline-name "$(PROOF_UID)" \
701 | --ci-stage build \
702 | --description "$(PROOF_UID): not setting static variables to nondet (will do during contract instrumentation)"
703 | else
704 | $(LITANI) add-job \
705 | --command \
706 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(NONDET_STATIC) $^ $@' \
707 | --inputs $^ \
708 | --outputs $@ \
709 | --stdout-file $(LOGDIR)/nondet_static-log.txt \
710 | --pipeline-name "$(PROOF_UID)" \
711 | --ci-stage build \
712 | --description "$(PROOF_UID): setting static variables to nondet"
713 | endif
714 |
715 | # Link CPROVER library if DFCC mode is on
716 | $(HARNESS_GOTO)0400.goto: $(HARNESS_GOTO)0300.goto
717 | ifneq ($(strip $(USE_DYNAMIC_FRAMES)),)
718 | $(LITANI) add-job \
719 | --command \
720 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(ADD_LIBRARY_FLAG) $(CBMC_OPT_CONFIG_LIBRARY) $^ $@' \
721 | --inputs $^ \
722 | --outputs $@ \
723 | --stdout-file $(LOGDIR)/linking-library-models-log.txt \
724 | --pipeline-name "$(PROOF_UID)" \
725 | --ci-stage build \
726 | --description "$(PROOF_UID): linking CPROVER library"
727 | else
728 | $(LITANI) add-job \
729 | --command 'cp $^ $@' \
730 | --inputs $^ \
731 | --outputs $@ \
732 | --stdout-file $(LOGDIR)/linking-library-models-log.txt \
733 | --pipeline-name "$(PROOF_UID)" \
734 | --ci-stage build \
735 | --description "$(PROOF_UID): not linking CPROVER library"
736 | endif
737 |
738 | # Early unwind all loops on DFCC mode; otherwise, only unwind loops in proof and project code
739 | $(HARNESS_GOTO)0500.goto: $(HARNESS_GOTO)0400.goto
740 | ifneq ($(strip $(USE_DYNAMIC_FRAMES)),)
741 | $(LITANI) add-job \
742 | --command \
743 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(UNWIND_0500_FLAGS) $^ $@' \
744 | --inputs $^ \
745 | --outputs $@ \
746 | --stdout-file $(LOGDIR)/unwind_loops-log.txt \
747 | --pipeline-name "$(PROOF_UID)" \
748 | --ci-stage build \
749 | --description $(UNWIND_0500_DESC)
750 | else ifneq ($(strip $(CODE_CONTRACTS)),)
751 | $(LITANI) add-job \
752 | --command \
753 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) $(CBMC_UNWINDSET) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $^ $@' \
754 | --inputs $^ \
755 | --outputs $@ \
756 | --stdout-file $(LOGDIR)/unwind_loops-log.txt \
757 | --pipeline-name "$(PROOF_UID)" \
758 | --ci-stage build \
759 | --description "$(PROOF_UID): unwinding loops in proof and project code"
760 | else
761 | $(LITANI) add-job \
762 | --command 'cp $^ $@' \
763 | --inputs $^ \
764 | --outputs $@ \
765 | --stdout-file $(LOGDIR)/unwind_loops-log.txt \
766 | --pipeline-name "$(PROOF_UID)" \
767 | --ci-stage build \
768 | --description "$(PROOF_UID): not unwinding loops"
769 | endif
770 |
771 | # Replace function contracts, check function contracts, instrument for loop contracts
772 | $(HARNESS_GOTO)0600.goto: $(HARNESS_GOTO)0500.goto
773 | $(LITANI) add-job \
774 | --command \
775 | '$(GOTO_INSTRUMENT) $(CBMC_USE_DYNAMIC_FRAMES) $(NONDET_STATIC) $(CBMC_VERBOSITY) $(CBMC_CHECK_FUNCTION_CONTRACTS) $(CBMC_USE_FUNCTION_CONTRACTS) $(CBMC_APPLY_LOOP_CONTRACTS) $^ $@' \
776 | --inputs $^ \
777 | --outputs $@ \
778 | --stdout-file $(LOGDIR)/check_function_contracts-log.txt \
779 | --pipeline-name "$(PROOF_UID)" \
780 | --ci-stage build \
781 | --description "$(PROOF_UID): checking function contracts"
782 |
783 | # Omit initialization of unused global variables (reduces problem size)
784 | $(HARNESS_GOTO)0700.goto: $(HARNESS_GOTO)0600.goto
785 | $(LITANI) add-job \
786 | --command \
787 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --slice-global-inits $^ $@' \
788 | --inputs $^ \
789 | --outputs $@ \
790 | --stdout-file $(LOGDIR)/slice_global_inits-log.txt \
791 | --pipeline-name "$(PROOF_UID)" \
792 | --ci-stage build \
793 | --description "$(PROOF_UID): slicing global initializations"
794 |
795 | # Omit unused functions (sharpens coverage calculations)
796 | $(HARNESS_GOTO)0800.goto: $(HARNESS_GOTO)0700.goto
797 | $(LITANI) add-job \
798 | --command \
799 | '$(GOTO_INSTRUMENT) $(CBMC_VERBOSITY) --drop-unused-functions $^ $@' \
800 | --inputs $^ \
801 | --outputs $@ \
802 | --stdout-file $(LOGDIR)/drop_unused_functions-log.txt \
803 | --pipeline-name "$(PROOF_UID)" \
804 | --ci-stage build \
805 | --description "$(PROOF_UID): dropping unused functions"
806 |
807 | # Final name for proof harness
808 | $(HARNESS_GOTO).goto: $(HARNESS_GOTO)0800.goto
809 | $(LITANI) add-job \
810 | --command 'cp $< $@' \
811 | --inputs $^ \
812 | --outputs $@ \
813 | --pipeline-name "$(PROOF_UID)" \
814 | --ci-stage build \
815 | --description "$(PROOF_UID): copying final goto-binary"
816 |
817 | ################################################################
818 | # Targets to run the analysis commands
819 |
820 | ifdef CBMCFLAGS
821 | ifeq ($(strip $(CODE_CONTRACTS)),)
822 | CBMCFLAGS += $(CBMC_UNWINDSET) $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_DEFAULT_UNWIND) $(CBMC_OPT_CONFIG_LIBRARY)
823 | else ifeq ($(strip $(USE_DYNAMIC_FRAMES)),)
824 | CBMCFLAGS += $(CBMC_CPROVER_LIBRARY_UNWINDSET) $(CBMC_OPT_CONFIG_LIBRARY)
825 | endif
826 | endif
827 |
828 | $(LOGDIR)/result.xml: $(HARNESS_GOTO).goto
829 | $(LITANI) add-job \
830 | $(POOL) \
831 | --command \
832 | '$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace --xml-ui $<' \
833 | --inputs $^ \
834 | --outputs $@ \
835 | --ci-stage test \
836 | --stdout-file $@ \
837 | $(MEMORY_PROFILING) \
838 | --ignore-returns 10 \
839 | --timeout $(CBMC_TIMEOUT) \
840 | --pipeline-name "$(PROOF_UID)" \
841 | --tags "stats-group:safety checks" \
842 | --stderr-file $(LOGDIR)/result-err-log.txt \
843 | --description "$(PROOF_UID): checking safety properties"
844 |
845 | $(LOGDIR)/result.txt: $(HARNESS_GOTO).goto
846 | $(LITANI) add-job \
847 | $(POOL) \
848 | --command \
849 | '$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --trace $<' \
850 | --inputs $^ \
851 | --outputs $@ \
852 | --ci-stage test \
853 | --stdout-file $@ \
854 | $(MEMORY_PROFILING) \
855 | --ignore-returns 10 \
856 | --timeout $(CBMC_TIMEOUT) \
857 | --pipeline-name "$(PROOF_UID)" \
858 | --tags "stats-group:safety checks" \
859 | --stderr-file $(LOGDIR)/result-err-log.txt \
860 | --description "$(PROOF_UID): checking safety properties"
861 |
862 | $(LOGDIR)/property.xml: $(HARNESS_GOTO).goto
863 | $(LITANI) add-job \
864 | --command \
865 | '$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(CBMC_FLAG_UNWINDING_ASSERTIONS) $(CHECKFLAGS) --show-properties --xml-ui $<' \
866 | --inputs $^ \
867 | --outputs $@ \
868 | --ci-stage test \
869 | --stdout-file $@ \
870 | --ignore-returns 10 \
871 | --pipeline-name "$(PROOF_UID)" \
872 | --stderr-file $(LOGDIR)/property-err-log.txt \
873 | --description "$(PROOF_UID): printing safety properties"
874 |
875 | $(LOGDIR)/coverage.xml: $(HARNESS_GOTO).goto
876 | $(LITANI) add-job \
877 | $(POOL) \
878 | --command \
879 | '$(CBMC) $(CBMC_VERBOSITY) $(CBMCFLAGS) $(COVERFLAGS) --cover location --xml-ui $<' \
880 | --inputs $^ \
881 | --outputs $@ \
882 | --ci-stage test \
883 | --stdout-file $@ \
884 | $(MEMORY_PROFILING) \
885 | --ignore-returns 10 \
886 | --timeout $(CBMC_TIMEOUT) \
887 | --pipeline-name "$(PROOF_UID)" \
888 | --tags "stats-group:coverage computation" \
889 | --stderr-file $(LOGDIR)/coverage-err-log.txt \
890 | --description "$(PROOF_UID): calculating coverage"
891 |
892 | COVERAGE ?= $(LOGDIR)/coverage.xml
893 | VIEWER_COVERAGE_FLAG ?= --coverage $(COVERAGE)
894 |
895 | $(PROOFDIR)/report: $(LOGDIR)/result.xml $(LOGDIR)/property.xml $(COVERAGE)
896 | $(LITANI) add-job \
897 | --command " $(VIEWER) \
898 | --result $(LOGDIR)/result.xml \
899 | $(VIEWER_COVERAGE_FLAG) \
900 | --property $(LOGDIR)/property.xml \
901 | --srcdir $(SRCDIR) \
902 | --goto $(HARNESS_GOTO).goto \
903 | --reportdir $(PROOFDIR)/report \
904 | --config $(PROOFDIR)/cbmc-viewer.json" \
905 | --inputs $^ \
906 | --outputs $(PROOFDIR)/report \
907 | --pipeline-name "$(PROOF_UID)" \
908 | --stdout-file $(LOGDIR)/viewer-log.txt \
909 | --ci-stage report \
910 | --description "$(PROOF_UID): generating report"
911 |
912 | litani-path:
913 | @echo $(LITANI)
914 |
915 | # ##############################################################
916 | # Phony Rules
917 | #
918 | # These rules provide a convenient way to run a single proof up to a
919 | # certain stage. Users can browse into a proof directory and run
920 | # "make -Bj 3 report" to generate a report for just that proof, or
921 | # "make goto" to build the goto binary. Under the hood, this runs litani
922 | # for just that proof.
923 |
924 | _goto: $(HARNESS_GOTO).goto
925 | goto:
926 | @ echo Running 'litani init'
927 | $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME)
928 | @ echo Running 'litani add-job'
929 | $(MAKE) -B _goto
930 | @ echo Running 'litani build'
931 | $(LITANI) run-build
932 |
933 | _result: $(LOGDIR)/result.txt
934 | result:
935 | @ echo Running 'litani init'
936 | $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME)
937 | @ echo Running 'litani add-job'
938 | $(MAKE) -B _result
939 | @ echo Running 'litani build'
940 | $(LITANI) run-build
941 |
942 | _property: $(LOGDIR)/property.xml
943 | property:
944 | @ echo Running 'litani init'
945 | $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME)
946 | @ echo Running 'litani add-job'
947 | $(MAKE) -B _property
948 | @ echo Running 'litani build'
949 | $(LITANI) run-build
950 |
951 | _coverage: $(LOGDIR)/coverage.xml
952 | coverage:
953 | @ echo Running 'litani init'
954 | $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME)
955 | @ echo Running 'litani add-job'
956 | $(MAKE) -B _coverage
957 | @ echo Running 'litani build'
958 | $(LITANI) run-build
959 |
960 | _report: $(PROOFDIR)/report
961 | report:
962 | @ echo Running 'litani init'
963 | $(LITANI) init $(INIT_POOLS) --project $(PROJECT_NAME)
964 | @ echo Running 'litani add-job'
965 | $(MAKE) -B _report
966 | @ echo Running 'litani build'
967 | $(LITANI) run-build
968 |
969 | _report_no_coverage:
970 | $(MAKE) COVERAGE="" VIEWER_COVERAGE_FLAG="" _report
971 | report-no-coverage:
972 | $(MAKE) COVERAGE="" VIEWER_COVERAGE_FLAG=" " report
973 |
974 | ################################################################
975 | # Targets to clean up after ourselves
976 | clean:
977 | -$(RM) $(DEPENDENT_GOTOS)
978 | -$(RM) TAGS*
979 | -$(RM) *~ \#*
980 | -$(RM) $(REWRITTEN_SOURCES) $(foreach rs,$(REWRITTEN_SOURCES),$(rs).json)
981 |
982 | veryclean: clean
983 | -$(RM) -r report
984 | -$(RM) -r $(LOGDIR) $(GOTODIR)
985 |
986 | .PHONY: \
987 | _coverage \
988 | _goto \
989 | _property \
990 | _report \
991 | _report_no_coverage \
992 | clean \
993 | coverage \
994 | goto \
995 | litani-path \
996 | property \
997 | report \
998 | report-no-coverage \
999 | result \
1000 | setup_dependencies \
1001 | testdeps \
1002 | veryclean \
1003 | #
1004 |
1005 | ################################################################
1006 |
1007 | # Run "make echo-proof-uid" to print the proof ID of a proof. This can be
1008 | # used by scripts to ensure that every proof has an ID, that there are
1009 | # no duplicates, etc.
1010 |
1011 | .PHONY: echo-proof-uid
1012 | echo-proof-uid:
1013 | @echo $(PROOF_UID)
1014 |
1015 | .PHONY: echo-project-name
1016 | echo-project-name:
1017 | @echo $(PROJECT_NAME)
1018 |
1019 | ################################################################
1020 |
1021 | # Project-specific targets requiring values defined above
1022 | sinclude $(PROOF_ROOT)/Makefile-project-targets
1023 |
1024 | # CI-specific targets to drive cbmc in CI
1025 | sinclude $(PROOF_ROOT)/Makefile-project-testing
1026 |
1027 | ################################################################
1028 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/README.md:
--------------------------------------------------------------------------------
1 | CBMC proofs
2 | ===========
3 |
4 | This directory contains the CBMC proofs. Each proof is in its own
5 | directory.
6 |
7 | This directory includes four Makefiles.
8 |
9 | One Makefile describes the basic workflow for building and running proofs:
10 |
11 | * Makefile.common:
12 | * make: builds the goto binary, does the cbmc property checking
13 | and coverage checking, and builds the final report.
14 | * make goto: builds the goto binary
15 | * make result: does cbmc property checking
16 | * make coverage: does cbmc coverage checking
17 | * make report: builds the final report
18 |
19 | Three included Makefiles describe project-specific settings and can override
20 | definitions in Makefile.common:
21 |
22 | * Makefile-project-defines: definitions like compiler flags
23 | required to build the goto binaries, and definitions to override
24 | definitions in Makefile.common.
25 | * Makefile-project-targets: other make targets needed for the project
26 | * Makefile-project-testing: other definitions and targets needed for
27 | unit testing or continuous integration.
28 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/629ec2a21d91ade13bfb995aace2223b36c4cd2e/test/cbmc/proofs/lib/__init__.py
--------------------------------------------------------------------------------
/test/cbmc/proofs/lib/print_tool_versions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | # SPDX-License-Identifier: MIT-0
5 |
6 |
7 | import logging
8 | import pathlib
9 | import shutil
10 | import subprocess
11 |
12 |
13 | _TOOLS = [
14 | "cadical",
15 | "cbmc",
16 | "cbmc-viewer",
17 | "cbmc-starter-kit-update",
18 | "kissat",
19 | "litani",
20 | ]
21 |
22 |
23 | def _format_versions(table):
24 | lines = [
25 | "",
26 | 'Tool Versions |
',
27 | ]
28 | for tool, version in table.items():
29 | if version:
30 | v_str = f'{version}
'
31 | else:
32 | v_str = 'not found'
33 | lines.append(
34 | f'{tool}: | '
36 | f'{v_str} |
')
37 | lines.append("
")
38 | return "\n".join(lines)
39 |
40 |
41 | def _get_tool_versions():
42 | ret = {}
43 | for tool in _TOOLS:
44 | err = f"Could not determine version of {tool}: "
45 | ret[tool] = None
46 | if not shutil.which(tool):
47 | logging.error("%s'%s' not found on $PATH", err, tool)
48 | continue
49 | cmd = [tool, "--version"]
50 | proc = subprocess.Popen(cmd, text=True, stdout=subprocess.PIPE)
51 | try:
52 | out, _ = proc.communicate(timeout=10)
53 | except subprocess.TimeoutExpired:
54 | logging.error("%s'%s --version' timed out", err, tool)
55 | continue
56 | if proc.returncode:
57 | logging.error(
58 | "%s'%s --version' returned %s", err, tool, str(proc.returncode))
59 | continue
60 | ret[tool] = out.strip()
61 | return ret
62 |
63 |
64 | def main():
65 | exe_name = pathlib.Path(__file__).name
66 | logging.basicConfig(format=f"{exe_name}: %(message)s")
67 |
68 | table = _get_tool_versions()
69 | out = _format_versions(table)
70 | print(out)
71 |
72 |
73 | if __name__ == "__main__":
74 | main()
75 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/lib/summarize.py:
--------------------------------------------------------------------------------
1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: MIT-0
3 |
4 | import argparse
5 | import json
6 | import logging
7 | import os
8 | import sys
9 |
10 |
11 | DESCRIPTION = """Print 2 tables in GitHub-flavored Markdown that summarize
12 | an execution of CBMC proofs."""
13 |
14 |
15 | def get_args():
16 | """Parse arguments for summarize script."""
17 | parser = argparse.ArgumentParser(description=DESCRIPTION)
18 | for arg in [{
19 | "flags": ["--run-file"],
20 | "help": "path to the Litani run.json file",
21 | "required": True,
22 | }]:
23 | flags = arg.pop("flags")
24 | parser.add_argument(*flags, **arg)
25 | return parser.parse_args()
26 |
27 |
28 | def _get_max_length_per_column_list(data):
29 | ret = [len(item) + 1 for item in data[0]]
30 | for row in data[1:]:
31 | for idx, item in enumerate(row):
32 | ret[idx] = max(ret[idx], len(item) + 1)
33 | return ret
34 |
35 |
36 | def _get_table_header_separator(max_length_per_column_list):
37 | line_sep = ""
38 | for max_length_of_word_in_col in max_length_per_column_list:
39 | line_sep += "|" + "-" * (max_length_of_word_in_col + 1)
40 | line_sep += "|\n"
41 | return line_sep
42 |
43 |
44 | def _get_entries(max_length_per_column_list, row_data):
45 | entries = []
46 | for row in row_data:
47 | entry = ""
48 | for idx, word in enumerate(row):
49 | max_length_of_word_in_col = max_length_per_column_list[idx]
50 | space_formatted_word = (max_length_of_word_in_col - len(word)) * " "
51 | entry += "| " + word + space_formatted_word
52 | entry += "|\n"
53 | entries.append(entry)
54 | return entries
55 |
56 |
57 | def _get_rendered_table(data):
58 | table = []
59 | max_length_per_column_list = _get_max_length_per_column_list(data)
60 | entries = _get_entries(max_length_per_column_list, data)
61 | for idx, entry in enumerate(entries):
62 | if idx == 1:
63 | line_sep = _get_table_header_separator(max_length_per_column_list)
64 | table.append(line_sep)
65 | table.append(entry)
66 | table.append("\n")
67 | return "".join(table)
68 |
69 |
70 | def _get_status_and_proof_summaries(run_dict):
71 | """Parse a dict representing a Litani run and create lists summarizing the
72 | proof results.
73 |
74 | Parameters
75 | ----------
76 | run_dict
77 | A dictionary representing a Litani run.
78 |
79 |
80 | Returns
81 | -------
82 | A list of 2 lists.
83 | The first sub-list maps a status to the number of proofs with that status.
84 | The second sub-list maps each proof to its status.
85 | """
86 | count_statuses = {}
87 | proofs = [["Proof", "Status"]]
88 | for proof_pipeline in run_dict["pipelines"]:
89 | status_pretty_name = proof_pipeline["status"].title().replace("_", " ")
90 | try:
91 | count_statuses[status_pretty_name] += 1
92 | except KeyError:
93 | count_statuses[status_pretty_name] = 1
94 | if proof_pipeline["name"] == "print_tool_versions":
95 | continue
96 | proofs.append([proof_pipeline["name"], status_pretty_name])
97 | statuses = [["Status", "Count"]]
98 | for status, count in count_statuses.items():
99 | statuses.append([status, str(count)])
100 | return [statuses, proofs]
101 |
102 |
103 | def print_proof_results(out_file):
104 | """
105 | Print 2 strings that summarize the proof results.
106 | When printing, each string will render as a GitHub flavored Markdown table.
107 | """
108 | output = "## Summary of CBMC proof results\n\n"
109 | with open(out_file, encoding='utf-8') as run_json:
110 | run_dict = json.load(run_json)
111 | status_table, proof_table = _get_status_and_proof_summaries(run_dict)
112 | for summary in (status_table, proof_table):
113 | output += _get_rendered_table(summary)
114 |
115 | print(output)
116 | sys.stdout.flush()
117 |
118 | github_summary_file = os.getenv("GITHUB_STEP_SUMMARY")
119 | if github_summary_file:
120 | with open(github_summary_file, "a") as handle:
121 | print(output, file=handle)
122 | handle.flush()
123 | else:
124 | logging.warning(
125 | "$GITHUB_STEP_SUMMARY not set, not writing summary file")
126 |
127 | msg = (
128 | "Click the 'Summary' button to view a Markdown table "
129 | "summarizing all proof results")
130 | if run_dict["status"] != "success":
131 | logging.error("Not all proofs passed.")
132 | logging.error(msg)
133 | sys.exit(1)
134 | logging.info(msg)
135 |
136 |
137 | if __name__ == '__main__':
138 | args = get_args()
139 | logging.basicConfig(format="%(levelname)s: %(message)s")
140 | try:
141 | print_proof_results(args.run_file)
142 | except Exception as ex: # pylint: disable=broad-except
143 | logging.critical("Could not print results. Exception: %s", str(ex))
--------------------------------------------------------------------------------
/test/cbmc/proofs/prepare.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | # SPDX-License-Identifier: Apache-2.0
5 |
6 |
7 | """Prepare the source tree for proofs in continuous integration."""
8 |
9 |
10 | import os
11 | import subprocess
12 |
13 |
14 | MAKEFILE = "Makefile"
15 | CBMC_BATCH_YAML = "cbmc-batch.yaml"
16 |
17 |
18 | def create_cbmc_batch_yaml(folder):
19 | """Run make to create cbmc-batch.yaml in folder."""
20 |
21 | try:
22 | subprocess.run(
23 | ["make", "-B", CBMC_BATCH_YAML],
24 | cwd=folder,
25 | stdout=subprocess.PIPE,
26 | stderr=subprocess.PIPE,
27 | universal_newlines=True,
28 | check=True
29 | )
30 | except subprocess.CalledProcessError as error:
31 | raise UserWarning("Failed to create {} in {}: "
32 | "command was '{}': "
33 | "error was '{}'"
34 | .format(CBMC_BATCH_YAML, folder,
35 | ' '.join(error.cmd),
36 | error.stderr.strip())) from None
37 |
38 |
39 | def create_cbmc_batch_yaml_files(root='.'):
40 | """Create cbmc-batch.yaml in all directories under root."""
41 |
42 | for folder, _, files in os.walk(root):
43 | if CBMC_BATCH_YAML in files and MAKEFILE in files:
44 | create_cbmc_batch_yaml(folder)
45 |
46 |
47 | def prepare():
48 | """Prepare the source tree for proofs in continuous integration."""
49 |
50 | create_cbmc_batch_yaml_files()
51 |
52 |
53 | if __name__ == "__main__":
54 | prepare()
55 |
--------------------------------------------------------------------------------
/test/cbmc/proofs/run-cbmc-proofs.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | # SPDX-License-Identifier: MIT-0
5 |
6 |
7 | import argparse
8 | import asyncio
9 | import json
10 | import logging
11 | import math
12 | import os
13 | import pathlib
14 | import re
15 | import subprocess
16 | import sys
17 | import tempfile
18 |
19 | from lib.summarize import print_proof_results
20 |
21 |
22 | DESCRIPTION = "Configure and run all CBMC proofs in parallel"
23 |
24 | # Keep the epilog hard-wrapped at 70 characters, as it gets printed
25 | # verbatim in the terminal. 70 characters stops here --------------> |
26 | EPILOG = """
27 | This tool automates the process of running `make report` in each of
28 | the CBMC proof directories. The tool calculates the dependency graph
29 | of all tasks needed to build, run, and report on all the proofs, and
30 | executes these tasks in parallel.
31 |
32 | The tool is roughly equivalent to doing this:
33 |
34 | litani init --project "my-cool-project";
35 |
36 | find . -name cbmc-proof.txt | while read -r proof; do
37 | pushd $(dirname ${proof});
38 |
39 | # The `make _report` rule adds a single proof to litani
40 | # without running it
41 | make _report;
42 |
43 | popd;
44 | done
45 |
46 | litani run-build;
47 |
48 | except that it is much faster and provides some convenience options.
49 | The CBMC CI runs this script with no arguments to build and run all
50 | proofs in parallel. The value of "my-cool-project" is taken from the
51 | PROJECT_NAME variable in Makefile-project-defines.
52 |
53 | The --no-standalone argument omits the `litani init` and `litani
54 | run-build`; use it when you want to add additional proof jobs, not
55 | just the CBMC ones. In that case, you would run `litani init`
56 | yourself; then run `run-cbmc-proofs --no-standalone`; add any
57 | additional jobs that you want to execute with `litani add-job`; and
58 | finally run `litani run-build`.
59 |
60 | The litani dashboard will be written under the `output` directory; the
61 | cbmc-viewer reports remain in the `$PROOF_DIR/report` directory. The
62 | HTML dashboard from the latest Litani run will always be symlinked to
63 | `output/latest/html/index.html`, so you can keep that page open in
64 | your browser and reload the page whenever you re-run this script.
65 | """
66 | # 70 characters stops here ----------------------------------------> |
67 |
68 |
69 | def get_project_name():
70 | cmd = [
71 | "make",
72 | "--no-print-directory",
73 | "-f", "Makefile.common",
74 | "echo-project-name",
75 | ]
76 | logging.debug(" ".join(cmd))
77 | proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False)
78 | if proc.returncode:
79 | logging.critical("could not run make to determine project name")
80 | sys.exit(1)
81 | if not proc.stdout.strip():
82 | logging.warning(
83 | "project name has not been set; using generic name instead. "
84 | "Set the PROJECT_NAME value in Makefile-project-defines to "
85 | "remove this warning")
86 | return ""
87 | return proc.stdout.strip()
88 |
89 |
90 | def get_args():
91 | pars = argparse.ArgumentParser(
92 | description=DESCRIPTION, epilog=EPILOG,
93 | formatter_class=argparse.RawDescriptionHelpFormatter)
94 | for arg in [{
95 | "flags": ["-j", "--parallel-jobs"],
96 | "type": int,
97 | "metavar": "N",
98 | "help": "run at most N proof jobs in parallel",
99 | }, {
100 | "flags": ["--fail-on-proof-failure"],
101 | "action": "store_true",
102 | "help": "exit with return code `10' if any proof failed"
103 | " (default: exit 0)",
104 | }, {
105 | "flags": ["--no-standalone"],
106 | "action": "store_true",
107 | "help": "only configure proofs: do not initialize nor run",
108 | }, {
109 | "flags": ["-p", "--proofs"],
110 | "nargs": "+",
111 | "metavar": "DIR",
112 | "help": "only run proof in directory DIR (can pass more than one)",
113 | }, {
114 | "flags": ["--project-name"],
115 | "metavar": "NAME",
116 | "default": get_project_name(),
117 | "help": "project name for report. Default: %(default)s",
118 | }, {
119 | "flags": ["--marker-file"],
120 | "metavar": "FILE",
121 | "default": "cbmc-proof.txt",
122 | "help": (
123 | "name of file that marks proof directories. Default: "
124 | "%(default)s"),
125 | }, {
126 | "flags": ["--no-memory-profile"],
127 | "action": "store_true",
128 | "help": "disable memory profiling, even if Litani supports it"
129 | }, {
130 | "flags": ["--no-expensive-limit"],
131 | "action": "store_true",
132 | "help": "do not limit parallelism of 'EXPENSIVE' jobs",
133 | }, {
134 | "flags": ["--expensive-jobs-parallelism"],
135 | "metavar": "N",
136 | "default": 1,
137 | "type": int,
138 | "help": (
139 | "how many proof jobs marked 'EXPENSIVE' to run in parallel. "
140 | "Default: %(default)s"),
141 | }, {
142 | "flags": ["--verbose"],
143 | "action": "store_true",
144 | "help": "verbose output",
145 | }, {
146 | "flags": ["--debug"],
147 | "action": "store_true",
148 | "help": "debug output",
149 | }, {
150 | "flags": ["--summarize"],
151 | "action": "store_true",
152 | "help": "summarize proof results with two tables on stdout",
153 | }, {
154 | "flags": ["--version"],
155 | "action": "version",
156 | "version": "CBMC starter kit 2.5",
157 | "help": "display version and exit"
158 | }]:
159 | flags = arg.pop("flags")
160 | pars.add_argument(*flags, **arg)
161 | return pars.parse_args()
162 |
163 |
164 | def set_up_logging(verbose):
165 | if verbose:
166 | level = logging.DEBUG
167 | else:
168 | level = logging.WARNING
169 | logging.basicConfig(
170 | format="run-cbmc-proofs: %(message)s", level=level)
171 |
172 |
173 | def task_pool_size():
174 | ret = os.cpu_count()
175 | if ret is None or ret < 3:
176 | return 1
177 | return ret - 2
178 |
179 |
180 | def print_counter(counter):
181 | # pylint: disable=consider-using-f-string
182 | print("\rConfiguring CBMC proofs: "
183 | "{complete:{width}} / {total:{width}}".format(**counter), end="", file=sys.stderr)
184 |
185 |
186 | def get_proof_dirs(proof_root, proof_list, marker_file):
187 | if proof_list is not None:
188 | proofs_remaining = list(proof_list)
189 | else:
190 | proofs_remaining = []
191 |
192 | for root, _, fyles in os.walk(proof_root):
193 | proof_name = str(pathlib.Path(root).name)
194 | if root != str(proof_root) and ".litani_cache_dir" in fyles:
195 | pathlib.Path(f"{root}/.litani_cache_dir").unlink()
196 | if proof_list and proof_name not in proof_list:
197 | continue
198 | if proof_list and proof_name in proofs_remaining:
199 | proofs_remaining.remove(proof_name)
200 | if marker_file in fyles:
201 | yield root
202 |
203 | if proofs_remaining:
204 | logging.critical(
205 | "The following proofs were not found: %s",
206 | ", ".join(proofs_remaining))
207 | sys.exit(1)
208 |
209 |
210 | def run_build(litani, jobs, fail_on_proof_failure, summarize):
211 | cmd = [str(litani), "run-build"]
212 | if jobs:
213 | cmd.extend(["-j", str(jobs)])
214 | if fail_on_proof_failure:
215 | cmd.append("--fail-on-pipeline-failure")
216 | if summarize:
217 | out_file = pathlib.Path(tempfile.gettempdir(), "run.json").resolve()
218 | cmd.extend(["--out-file", str(out_file)])
219 |
220 | logging.debug(" ".join(cmd))
221 | proc = subprocess.run(cmd, check=False)
222 |
223 | if proc.returncode and not fail_on_proof_failure:
224 | logging.critical("Failed to run litani run-build")
225 | sys.exit(1)
226 |
227 | if summarize:
228 | print_proof_results(out_file)
229 | out_file.unlink()
230 |
231 | if proc.returncode:
232 | logging.error("One or more proofs failed")
233 | sys.exit(10)
234 |
235 | def get_litani_path(proof_root):
236 | cmd = [
237 | "make",
238 | "--no-print-directory",
239 | f"PROOF_ROOT={proof_root}",
240 | "-f", "Makefile.common",
241 | "litani-path",
242 | ]
243 | logging.debug(" ".join(cmd))
244 | proc = subprocess.run(cmd, universal_newlines=True, stdout=subprocess.PIPE, check=False)
245 | if proc.returncode:
246 | logging.critical("Could not determine path to litani")
247 | sys.exit(1)
248 | return proc.stdout.strip()
249 |
250 |
251 | def get_litani_capabilities(litani_path):
252 | cmd = [litani_path, "print-capabilities"]
253 | proc = subprocess.run(
254 | cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, check=False)
255 | if proc.returncode:
256 | return []
257 | try:
258 | return json.loads(proc.stdout)
259 | except RuntimeError:
260 | logging.warning("Could not load litani capabilities: '%s'", proc.stdout)
261 | return []
262 |
263 |
264 | def check_uid_uniqueness(proof_dir, proof_uids):
265 | with (pathlib.Path(proof_dir) / "Makefile").open() as handle:
266 | for line in handle:
267 | match = re.match(r"^PROOF_UID\s*=\s*(?P\w+)", line)
268 | if not match:
269 | continue
270 | if match["uid"] not in proof_uids:
271 | proof_uids[match["uid"]] = proof_dir
272 | return
273 |
274 | logging.critical(
275 | "The Makefile in directory '%s' should have a different "
276 | "PROOF_UID than the Makefile in directory '%s'",
277 | proof_dir, proof_uids[match["uid"]])
278 | sys.exit(1)
279 |
280 | logging.critical(
281 | "The Makefile in directory '%s' should contain a line like", proof_dir)
282 | logging.critical("PROOF_UID = ...")
283 | logging.critical("with a unique identifier for the proof.")
284 | sys.exit(1)
285 |
286 |
287 | def should_enable_memory_profiling(litani_caps, args):
288 | if args.no_memory_profile:
289 | return False
290 | return "memory_profile" in litani_caps
291 |
292 |
293 | def should_enable_pools(litani_caps, args):
294 | if args.no_expensive_limit:
295 | return False
296 | return "pools" in litani_caps
297 |
298 |
299 | async def configure_proof_dirs( # pylint: disable=too-many-arguments
300 | queue, counter, proof_uids, enable_pools, enable_memory_profiling, debug):
301 | while True:
302 | print_counter(counter)
303 | path = str(await queue.get())
304 |
305 | check_uid_uniqueness(path, proof_uids)
306 |
307 | pools = ["ENABLE_POOLS=true"] if enable_pools else []
308 | profiling = [
309 | "ENABLE_MEMORY_PROFILING=true"] if enable_memory_profiling else []
310 |
311 | # Allow interactive tasks to preempt proof configuration
312 | proc = await asyncio.create_subprocess_exec(
313 | "nice", "-n", "15", "make", *pools,
314 | *profiling, "-B", "_report", "" if debug else "--quiet", cwd=path,
315 | stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
316 | stdout, stderr = await proc.communicate()
317 | logging.debug("returncode: %s", str(proc.returncode))
318 | logging.debug("stdout:")
319 | for line in stdout.decode().splitlines():
320 | logging.debug(line)
321 | logging.debug("stderr:")
322 | for line in stderr.decode().splitlines():
323 | logging.debug(line)
324 |
325 | counter["fail" if proc.returncode else "pass"].append(path)
326 | counter["complete"] += 1
327 |
328 | print_counter(counter)
329 | queue.task_done()
330 |
331 |
332 | async def main(): # pylint: disable=too-many-locals
333 | args = get_args()
334 | set_up_logging(args.verbose)
335 |
336 | proof_root = pathlib.Path(os.getcwd())
337 | litani = get_litani_path(proof_root)
338 |
339 | litani_caps = get_litani_capabilities(litani)
340 | enable_pools = should_enable_pools(litani_caps, args)
341 | init_pools = [
342 | "--pools", f"expensive:{args.expensive_jobs_parallelism}"
343 | ] if enable_pools else []
344 |
345 | if not args.no_standalone:
346 | cmd = [
347 | str(litani), "init", *init_pools, "--project", args.project_name,
348 | "--no-print-out-dir",
349 | ]
350 |
351 | if "output_directory_flags" in litani_caps:
352 | out_prefix = proof_root / "output"
353 | out_symlink = out_prefix / "latest"
354 | out_index = out_symlink / "html" / "index.html"
355 | cmd.extend([
356 | "--output-prefix", str(out_prefix),
357 | "--output-symlink", str(out_symlink),
358 | ])
359 | print(
360 | "\nFor your convenience, the output of this run will be symbolically linked to ",
361 | out_index, "\n")
362 |
363 | logging.debug(" ".join(cmd))
364 | proc = subprocess.run(cmd, check=False)
365 | if proc.returncode:
366 | logging.critical("Failed to run litani init")
367 | sys.exit(1)
368 |
369 | proof_dirs = list(get_proof_dirs(
370 | proof_root, args.proofs, args.marker_file))
371 | if not proof_dirs:
372 | logging.critical("No proof directories found")
373 | sys.exit(1)
374 |
375 | proof_queue = asyncio.Queue()
376 | for proof_dir in proof_dirs:
377 | proof_queue.put_nowait(proof_dir)
378 |
379 | counter = {
380 | "pass": [],
381 | "fail": [],
382 | "complete": 0,
383 | "total": len(proof_dirs),
384 | "width": int(math.log10(len(proof_dirs))) + 1
385 | }
386 |
387 | proof_uids = {}
388 | tasks = []
389 |
390 | enable_memory_profiling = should_enable_memory_profiling(litani_caps, args)
391 |
392 | for _ in range(task_pool_size()):
393 | task = asyncio.create_task(configure_proof_dirs(
394 | proof_queue, counter, proof_uids, enable_pools,
395 | enable_memory_profiling, args.debug))
396 | tasks.append(task)
397 |
398 | await proof_queue.join()
399 |
400 | print_counter(counter)
401 | print("", file=sys.stderr)
402 |
403 | if counter["fail"]:
404 | logging.critical(
405 | "Failed to configure the following proofs:\n%s", "\n".join(
406 | [str(f) for f in counter["fail"]]))
407 | sys.exit(1)
408 |
409 | if not args.no_standalone:
410 | run_build(litani, args.parallel_jobs, args.fail_on_proof_failure, args.summarize)
411 |
412 |
413 | if __name__ == "__main__":
414 | asyncio.run(main())
415 |
--------------------------------------------------------------------------------
/test/cbmc/sources/README.md:
--------------------------------------------------------------------------------
1 | CBMC proof source code
2 | ======================
3 |
4 | This directory contains source code written for CBMC proofs. It is
5 | common to write some code to model aspects of the system under test,
6 | and this code goes here.
7 |
--------------------------------------------------------------------------------
/test/cbmc/stubs/README.md:
--------------------------------------------------------------------------------
1 | CBMC proof stubs
2 | ======================
3 |
4 | This directory contains the stubs written for CBMC proofs. It is
5 | common to stub out functionality like network send and receive methods
6 | when writing a CBMC proof, and the code for these stubs goes here.
7 |
--------------------------------------------------------------------------------
/test/include/fleet_provisioning_config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * AWS IoT Fleet Provisioning v1.2.1
3 | * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | *
5 | * SPDX-License-Identifier: MIT
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | * this software and associated documentation files (the "Software"), to deal in
9 | * the Software without restriction, including without limitation the rights to
10 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | * the Software, and to permit persons to whom the Software is furnished to do so,
12 | * subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | /**
26 | * @file fleet_provisioning_config.h
27 | * @brief Config values for testing the AWS IoT Fleet Provisioning Library.
28 | */
29 |
30 | #ifndef FLEET_PROVISIONING_CONFIG_H_
31 | #define FLEET_PROVISIONING_CONFIG_H_
32 |
33 | #include
34 |
35 | #ifdef DISABLE_LOGGING
36 | #ifndef LogError
37 | #define LogError( message )
38 | #endif
39 | #ifndef LogWarn
40 | #define LogWarn( message )
41 | #endif
42 |
43 | #ifndef LogInfo
44 | #define LogInfo( message )
45 | #endif
46 |
47 | #ifndef LogDebug
48 | #define LogDebug( message )
49 | #endif
50 |
51 | #else /* ! DISABLE_LOGGING */
52 | #define LogError( message ) printf( "Error: " ); printf message; printf( "\n" )
53 |
54 | #define LogWarn( message ) printf( "Warn: " ); printf message; printf( "\n" )
55 |
56 | #define LogInfo( message ) printf( "Info: " ); printf message; printf( "\n" )
57 |
58 | #define LogDebug( message ) printf( "Debug: " ); printf message; printf( "\n" )
59 | #endif /* DISABLE_LOGGING */
60 |
61 | #endif /* FLEET_PROVISIONING_CONFIG_H_ */
62 |
--------------------------------------------------------------------------------
/test/unit-test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Include filepaths for Fleet Provisioning library.
2 | include( ${MODULE_ROOT_DIR}/fleetprovisioningFilePaths.cmake )
3 |
4 | set( library_name "fleet_provisioning" )
5 | set( library_target_name "${library_name}_target" )
6 | set( utest_binary_name "${library_name}_utest" )
7 |
8 | # =========================== Library ==============================
9 |
10 | # List of library source files.
11 | list( APPEND library_source_files
12 | ${FLEET_PROVISIONING_SOURCES} )
13 |
14 | # List of library include directories.
15 | list( APPEND library_include_directories
16 | ${FLEET_PROVISIONING_INCLUDE_PUBLIC_DIRS}
17 | "${CMAKE_CURRENT_LIST_DIR}/../include" )
18 |
19 | # Create a target for building library.
20 | create_library_target( ${library_target_name}
21 | "${library_source_files}"
22 | "${library_include_directories}" )
23 |
24 | # =========================== Test Binary ==============================
25 |
26 | # The source file containing the unit tests.
27 | set( utest_source_file "fleet_provisioning_utest.c" )
28 |
29 | # The list of include directories for the test binary target.
30 | list( APPEND utest_include_directories
31 | ${FLEET_PROVISIONING_INCLUDE_PUBLIC_DIRS} )
32 |
33 | # Libraries to be linked while building the test binary.
34 | list( APPEND utest_link_list
35 | lib${library_target_name}.a )
36 |
37 | # The targets on which the test binary target depends.
38 | list( APPEND utest_dep_list
39 | ${library_target_name} )
40 |
41 | # Create a target for the test binary.
42 | create_test_binary_target( ${utest_binary_name}
43 | ${utest_source_file}
44 | "${utest_link_list}"
45 | "${utest_dep_list}"
46 | "${test_include_directories}" )
47 |
--------------------------------------------------------------------------------
/test/unit-test/unity_build.cmake:
--------------------------------------------------------------------------------
1 | # Macro to clone the Unity submodule.
2 | macro( clone_unity )
3 | find_package( Git REQUIRED )
4 | message( "Cloning Unity submodule." )
5 | execute_process( COMMAND rm -rf ${UNITY_DIR}
6 | COMMAND ${GIT_EXECUTABLE} submodule update --checkout --init --recursive ${UNITY_DIR}
7 | WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
8 | RESULT_VARIABLE UNITY_CLONE_RESULT )
9 |
10 | if( NOT ${UNITY_CLONE_RESULT} STREQUAL "0" )
11 | message( FATAL_ERROR "Failed to clone Unity submodule." )
12 | endif()
13 | endmacro()
14 |
15 | # Macro to add library target for Unity to build configuration.
16 | macro( add_unity_target )
17 | add_library( unity STATIC
18 | "${UNITY_DIR}/src/unity.c"
19 | "${UNITY_DIR}/extras/fixture/src/unity_fixture.c"
20 | "${UNITY_DIR}/extras/memory/src/unity_memory.c" )
21 |
22 | target_include_directories( unity PUBLIC
23 | "${UNITY_DIR}/src/"
24 | "${UNITY_DIR}/extras/fixture/src"
25 | "${UNITY_DIR}/extras/memory/src" )
26 |
27 | set_target_properties( unity PROPERTIES
28 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
29 | POSITION_INDEPENDENT_CODE ON )
30 |
31 | target_link_libraries( unity )
32 | endmacro()
33 |
--------------------------------------------------------------------------------
/tools/coverity/README.md:
--------------------------------------------------------------------------------
1 | # Static code analysis for AWS IoT Fleet Provisioning Library
2 | This directory is made for the purpose of statically testing the MISRA C:2012 compliance of AWS IoT Fleet Provisioning Library using
3 | [Synopsys Coverity](https://www.synopsys.com/software-integrity/security-testing/static-analysis-sast.html) static analysis tool.
4 | To that end, this directory provides a [configuration file](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/blob/main/tools/coverity/misra.config) to use when
5 | building a binary for the tool to analyze.
6 |
7 | > **Note**
8 | For generating the report as outlined below, we have used Coverity version 2023.6.1.
9 |
10 | For details regarding the suppressed violations in the report (which can be generated using the instructions described below), please
11 | see the [MISRA.md](https://github.com/aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk/blob/main/MISRA.md) file.
12 |
13 | ## Getting Started
14 | ### Prerequisites
15 | You can run this on a platform supported by Coverity. The list and other details can be found [here](https://documentation.blackduck.com/bundle/coverity-docs-2024.9/page/deploy-install-guide/topics/supported_platforms_for_coverity_analysis.html).
16 | To compile and run the Coverity target successfully, you must have the following:
17 |
18 | 1. CMake version > 3.13.0 (You can check whether you have this by typing `cmake --version`)
19 | 2. GCC compiler
20 | - You can see the downloading and installation instructions [here](https://gcc.gnu.org/install/).
21 | 3. Download the repo and include the submodules using the following commands.
22 | - `git clone --recurse-submodules git@github.com:aws/Fleet-Provisioning-for-AWS-IoT-embedded-sdk.git ./Fleet-Provisioning-for-AWS-IoT-embedded-sdk`
23 | - `cd ./Fleet-Provisioning-for-AWS-IoT-embedded-sdk`
24 | - `git submodule update --checkout --init --recursive`
25 |
26 | ### To build and run coverity:
27 | Go to the root directory of the library and run the following commands in terminal:
28 | 1. Update the compiler configuration in Coverity
29 | ~~~
30 | cov-configure --force --compiler cc --comptype gcc
31 | ~~~
32 | 2. Create the build files using CMake in a `build` directory
33 | ~~~
34 | cmake -B build -S test -DCOV_ANALYSIS=1
35 | ~~~
36 | 3. Go to the build directory and copy the coverity configuration file
37 | ~~~
38 | cd build/
39 | ~~~
40 | 4. Build the static analysis target
41 | ~~~
42 | cov-build --emit-complementary-info --dir cov-out make coverity_analysis
43 | ~~~
44 | 5. Go to the Coverity output directory (`cov-out`) and begin Coverity static analysis
45 | ~~~
46 | cd cov-out/
47 | cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')"
48 | ~~~
49 | 6. Format the errors in HTML format so that it is more readable while removing the test and build directory from the report
50 | ~~~
51 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out;
52 | ~~~
53 | 7. Format the errors in JSON format to perform a jq query to get a simplified list of any exceptions.
54 | NOTE: A blank output means there are no defects that aren't being suppressed by the config or inline comments.
55 | ~~~
56 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json;
57 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n";
58 | jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr;
59 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n";
60 | ~~~
61 |
62 | For your convenience the commands above are below to be copy/pasted into a UNIX command friendly terminal.
63 | ~~~
64 | cov-configure --force --compiler cc --comptype gcc;
65 | cmake -B build -S test -DCOV_ANALYSIS=1;
66 | cd build/;
67 | cov-build --emit-complementary-info --dir cov-out make coverity_analysis;
68 | cd cov-out/
69 | cov-analyze --dir . --coding-standard-config ../../tools/coverity/misra.config --tu-pattern "file('.*/source/.*')";
70 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --html-output html-out;
71 | cov-format-errors --dir . --file "source" --exclude-files '(/build/|/test/)' --json-output-v2 defects.json;
72 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Below-------------------------\n";
73 | jq '.issues[] | .events[] | .eventTag ' defects.json | sort | uniq -c | sort -nr;
74 | echo -e "\n-------------------------Non-Suppresed Deviations, if any, Listed Above-------------------------\n";
75 | cd ../../;
76 | ~~~
77 |
78 | You should now have the HTML formatted violations list in a directory named `build/cov-out/html-output`.
79 | With the current configuration and the provided project, you should not see any deviations.
80 |
--------------------------------------------------------------------------------
/tools/coverity/misra.config:
--------------------------------------------------------------------------------
1 | {
2 | "version" : "2.0",
3 | "standard" : "c2012",
4 | "title": "Coverity MISRA Configuration",
5 | "deviations" : [
6 | {
7 | "deviation": "Directive 4.9",
8 | "reason": "Allow inclusion of function like macros. Asserts, logging, and topic string macros use function like macros."
9 | },
10 | {
11 | "deviation": "Rule 2.5",
12 | "reason": "Allow unused macros. Macros defined for topic strings are not used by the library, but are part of the API."
13 | },
14 | {
15 | "deviation": "Rule 3.1",
16 | "reason": "Allow nested comments. C++ style `//` comments are used in example code within Doxygen documentation blocks."
17 | },
18 | {
19 | "deviation": "Rule 8.7",
20 | "reason": "API functions are not used by library. They must be externally visible in order to be used by the application."
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/tools/unity/coverage.cmake:
--------------------------------------------------------------------------------
1 | cmake_minimum_required( VERSION 3.13 )
2 | set( BINARY_DIR ${CMAKE_BINARY_DIR} )
3 |
4 | # Reset coverage counters.
5 | execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR}
6 | --base-directory ${CMAKE_BINARY_DIR}
7 | --zerocounters )
8 |
9 | # Create directory for results.
10 | execute_process( COMMAND mkdir -p ${CMAKE_BINARY_DIR}/coverage )
11 |
12 | # Generate "baseline" coverage data with zero coverage for every instrumented
13 | # line. This is later combined with the coverage data from test run to ensure
14 | # that the percentage of total lines covered is correct even when not all source
15 | # code files were loaded during the test.
16 | execute_process( COMMAND lcov --directory ${CMAKE_BINARY_DIR}
17 | --base-directory ${CMAKE_BINARY_DIR}
18 | --initial
19 | --capture
20 | --rc lcov_branch_coverage=1
21 | --rc genhtml_branch_coverage=1
22 | --output-file=${CMAKE_BINARY_DIR}/base_coverage.info )
23 |
24 | # Capture all the test binaries.
25 | file( GLOB files "${CMAKE_BINARY_DIR}/bin/tests/*" )
26 |
27 | # Create an empty report file.
28 | set( REPORT_FILE ${CMAKE_BINARY_DIR}/utest_report.txt )
29 | file( WRITE ${REPORT_FILE} "" )
30 |
31 | # Execute all test binaries and capture all the output in the report file.
32 | foreach( testname ${files} )
33 | get_filename_component( test ${testname} NAME_WLE )
34 | message( "Running ${testname}" )
35 | execute_process( COMMAND ${testname} OUTPUT_FILE ${CMAKE_BINARY_DIR}/${test}_out.txt )
36 |
37 | # Append the test run output to the report file.
38 | file( READ ${CMAKE_BINARY_DIR}/${test}_out.txt CONTENTS )
39 | file( APPEND ${REPORT_FILE} "${CONTENTS}" )
40 | endforeach()
41 |
42 | # Generate Junit style xml output.
43 | execute_process( COMMAND ruby
44 | ${UNITY_DIR}/auto/parse_output.rb
45 | -xml ${REPORT_FILE}
46 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} )
47 |
48 | # Capture coverage data after test run.
49 | execute_process( COMMAND lcov --capture
50 | --rc lcov_branch_coverage=1
51 | --rc genhtml_branch_coverage=1
52 | --base-directory ${CMAKE_BINARY_DIR}
53 | --directory ${CMAKE_BINARY_DIR}
54 | --output-file ${CMAKE_BINARY_DIR}/second_coverage.info )
55 |
56 | # Combine baseline coverage data (zeros) with the coverage data from test run.
57 | execute_process( COMMAND lcov --base-directory ${CMAKE_BINARY_DIR}
58 | --directory ${CMAKE_BINARY_DIR}
59 | --add-tracefile ${CMAKE_BINARY_DIR}/base_coverage.info
60 | --add-tracefile ${CMAKE_BINARY_DIR}/second_coverage.info
61 | --output-file ${CMAKE_BINARY_DIR}/coverage.info
62 | --no-external
63 | --rc lcov_branch_coverage=1 )
64 |
65 | # Generate HTML Report.
66 | execute_process( COMMAND genhtml --rc lcov_branch_coverage=1
67 | --branch-coverage
68 | --output-directory ${CMAKE_BINARY_DIR}/coverage
69 | ${CMAKE_BINARY_DIR}/coverage.info )
70 |
--------------------------------------------------------------------------------
/tools/unity/create_test.cmake:
--------------------------------------------------------------------------------
1 | # Function to create the test executable.
2 | function( create_test_binary_target test_name
3 | test_src
4 | link_list
5 | dep_list
6 | include_list )
7 | include ( CTest )
8 | get_filename_component( test_src_absolute ${test_src} ABSOLUTE )
9 |
10 | # Generate test runner file.
11 | add_custom_command( OUTPUT ${test_name}_runner.c
12 | COMMAND ruby ${UNITY_DIR}/auto/generate_test_runner.rb
13 | ${MODULE_ROOT_DIR}/tools/unity/project.yml
14 | ${test_src_absolute}
15 | ${test_name}_runner.c
16 | DEPENDS ${test_src} )
17 |
18 | add_executable( ${test_name} ${test_src} ${test_name}_runner.c )
19 |
20 | set_target_properties( ${test_name} PROPERTIES
21 | COMPILE_FLAG "-O0 -ggdb"
22 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/tests"
23 | INSTALL_RPATH_USE_LINK_PATH TRUE
24 | LINK_FLAGS "-Wl,-rpath,${CMAKE_BINARY_DIR}/lib \
25 | -Wl,-rpath,${CMAKE_CURRENT_BINARY_DIR}/lib" )
26 |
27 | target_include_directories( ${test_name} PUBLIC ${mocks_dir} ${include_list} )
28 |
29 | target_link_directories( ${test_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} )
30 |
31 | # Link all libraries sent through parameters.
32 | foreach( link IN LISTS link_list )
33 | target_link_libraries( ${test_name} ${link} )
34 | endforeach()
35 |
36 | # Add dependency to all the dep_list parameter.
37 | foreach( dependency IN LISTS dep_list )
38 | add_dependencies( ${test_name} ${dependency} )
39 | target_link_libraries( ${test_name} ${dependency} )
40 | endforeach()
41 |
42 | target_link_libraries( ${test_name} -lgcov unity )
43 | target_link_directories( ${test_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/lib )
44 |
45 | add_test( NAME ${test_name}
46 | COMMAND ${CMAKE_BINARY_DIR}/bin/tests/${test_name}
47 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} )
48 | endfunction()
49 |
50 | # Function to create target for library under test.
51 | function( create_library_target target_name
52 | src_file
53 | include_list )
54 | add_library( ${target_name} STATIC ${src_file} )
55 | target_include_directories( ${target_name} PUBLIC ${include_list} )
56 |
57 | set_target_properties( ${target_name} PROPERTIES
58 | COMPILE_FLAGS "-Wextra -Wpedantic \
59 | -fprofile-arcs -ftest-coverage -fprofile-generate \
60 | -Wno-unused-but-set-variable"
61 | LINK_FLAGS "-fprofile-arcs -ftest-coverage \
62 | -fprofile-generate "
63 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib )
64 | endfunction()
65 |
--------------------------------------------------------------------------------
/tools/unity/project.yml:
--------------------------------------------------------------------------------
1 | :unity:
2 | :when_no_prototypes: :warn
3 | :enforce_strict_ordering: TRUE
4 | :treat_as:
5 | uint8: HEX8
6 | uint16: HEX16
7 | uint32: UINT32
8 | int8: INT8
9 | bool: UINT8
10 | :treat_externs: :exclude
11 | :weak: __attribute__((weak))
12 | :treat_externs: :include
13 |
--------------------------------------------------------------------------------